Skip to content

fdroid update crashes on duplicate permission

If an app declares a permission twice, and one of the declarations has maxSdkVersion set while the other has not, fdroid update crashes with a stack trace, requiring to check the code to find out what went wrong (and giving no clue which APK file caused the crash). Example (APK attached: sadLogic.HomeCentral_8.apk):

uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' maxSdkVersion='18'
uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'

Trace:

2025-05-14 21:10:14,666 CRITICAL: Unknown exception found!
Traceback (most recent call last):
  File "/mnt/data/src/git/fdroidserver/fdroid", line 22, in <module>
    fdroidserver.__main__.main()
  File "/home/git/repos/fdroidserver_iod/fdroidserver/__main__.py", line 222, in main
    raise e
  File "/home/git/repos/fdroidserver_iod/fdroidserver/__main__.py", line 203, in main
    mod.main()
  File "/home/git/repos/fdroidserver_iod/fdroidserver/update.py", line 2594, in main
    fdroidserver.index.make(repoapps, apks, repodirs[0], False)
  File "/home/git/repos/fdroidserver_iod/fdroidserver/index.py", line 121, in make
    make_v0(sortedapps, apks, repodir, repodict, requestsdict,
  File "/home/git/repos/fdroidserver_iod/fdroidserver/index.py", line 1274, in make_v0
    sorted_permissions = sorted(apk['uses-permission'])
TypeError: '<' not supported between instances of 'NoneType' and 'int'

While from this stack trace, one might be able to deduce what happened – it remains completely unclear which APK file has this issue. With hundreds or thousands of apps in the repository (like at F-Droid.org or IzzyOnDroid), this can be "fun" to figure. So as a quick work-around, giving a more meaningful message (and especially mentioning the culprit), we've applied this for now:

diff --git a/fdroidserver/index.py b/fdroidserver/index.py
index 69237149..4434079e 100644
--- a/fdroidserver/index.py
+++ b/fdroidserver/index.py
@@ -1257,7 +1271,10 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
                 addElement('sig', apk['sig'], doc, apkel)

                 old_permissions = set()
-                sorted_permissions = sorted(apk['uses-permission'])
+                try:
+                    sorted_permissions = sorted(apk['uses-permission'])
+                except Exception:
+                    raise FDroidException("Failed to sort permissions for {0}: {1}".format(apk['apkName'], ', '.join(map(str,apk['uses-permission']))))
                 for perm in sorted_permissions:
                     perm_name = perm[0]
                     if perm_name.startswith("android.permission."):

So at least "offender" and "cause" become immediately clear, and the offending APK can be moved out as a "quick remedy" to get things working again:

2025-05-15 10:34:38,494 CRITICAL: Failed to sort permissions for sadLogic.HomeCentral_8.apk: ['android.permission.WRITE_EXTERNAL_STORAGE', 18], ['android.permission.WRITE_EXTERNAL_STORAGE', None], ['android.permission.WAKE_LOCK', None], ['android.permission.INTERNET', None], ['android.permission.RECEIVE_BOOT_COMPLETED', None], ['android.permission.FOREGROUND_SERVICE', None], ['android.permission.WRITE_SETTINGS', None], ['android.permission.ACCESS_NOTIFICATION_POLICY', None], ['android.permission.READ_EXTERNAL_STORAGE', None], ['android.permission.REQUEST_INSTALL_PACKAGES', None]

I'm intentionally not providing this via an MR as I feel the proper handling should be throwing that message, but then continuing while ignoring the affected APK, so automated runs are not broken. Such occurrences should be rather rare, though – but can happen (and not just in binary repos). Up to you to use the patch as-is, or change the handling to ignore the APK as proposed.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information