permissions-dispatcher/PermissionsDispatcher · error · MixPermissionTypeException

Method '${e.simpleString()}()' defines '$permissionName' wit

Error message

Method '${e.simpleString()}()' defines '$permissionName' with other permissions at the same time.

What it means

Thrown by checkMixPermissionType in Validators.kt:117 via MixPermissionTypeException. Special permissions WRITE_SETTINGS and SYSTEM_ALERT_WINDOW are granted through Settings screens, not the runtime permission dialog, so they cannot be combined with normal runtime permissions in one @NeedsPermission request; the generated flow cannot handle the mixed grant mechanism.

Source

Thrown at processor/src/main/kotlin/permissions/dispatcher/processor/util/Validators.kt:117

        }
        if (numParams < params.size) {
            throw WrongParametersException(it, numParams, requiredType)
        }
        // maximum params size is 1
        params.forEach { param ->
            if (!TYPE_UTILS.isSameType(param.asType(), requiredType)) {
                throw WrongParametersException(it, numParams, requiredType)
            }
        }
    }
}

fun <A : Annotation> checkMixPermissionType(items: List<ExecutableElement>, annotationClass: Class<A>) {
    items.forEach {
        val permissionValue = it.getAnnotation(annotationClass).permissionValue()
        if (permissionValue.size > 1) {
            if (permissionValue.contains(WRITE_SETTINGS)) {
                throw MixPermissionTypeException(it, WRITE_SETTINGS)
            } else if (permissionValue.contains(SYSTEM_ALERT_WINDOW)) {
                throw MixPermissionTypeException(it, SYSTEM_ALERT_WINDOW)
            }
        }
    }
}

fun checkSpecialPermissionsWithNeverAskAgain(items: List<ExecutableElement>, annotationClass: Class<OnNeverAskAgain> = OnNeverAskAgain::class.java) {
    items.forEach {
        val permissionValue = it.getAnnotation(annotationClass).permissionValue()
        if (permissionValue.contains(WRITE_SETTINGS) || permissionValue.contains(SYSTEM_ALERT_WINDOW)) {
            throw SpecialPermissionsWithNeverAskAgainException()
        }
    }
}

fun checkDuplicatedMethodName(items: List<ExecutableElement>) {
    items.forEach { item ->

View on GitHub (pinned to 74b532bf1f)

Solutions

  1. Split into separate methods: one annotated only with the special permission, another with the normal runtime permissions.
  2. Request the special permission via its dedicated flow (ACTION_MANAGE_WRITE_SETTINGS / ACTION_MANAGE_OVERLAY_PERMISSION intents) instead of @NeedsPermission.
  3. Remove the special permission from the combined list if it is not actually required.

Example fix

// before
@NeedsPermission(Manifest.permission.CAMERA, Manifest.permission.WRITE_SETTINGS)
fun showCamera() { }

// after
@NeedsPermission(Manifest.permission.CAMERA)
fun showCamera() { }
// handle WRITE_SETTINGS separately via Settings intent flow
Defensive patterns

Strategy: validation

Validate before calling

val special = setOf(WRITE_SETTINGS, SYSTEM_ALERT_WINDOW)
require(!(requestedPermissions.size > 1 && requestedPermissions.any { it in special })) {
    "Special permissions cannot be combined with other permissions"
}

Try / catch

try {
    build()
} catch (e: CompilationError) {
    logger.error("Do not mix WRITE_SETTINGS/SYSTEM_ALERT_WINDOW with runtime permissions", e)
}

Prevention

When it happens

Trigger: Declaring @NeedsPermission(Manifest.permission.WRITE_SETTINGS, Manifest.permission.CAMERA) or @NeedsPermission(Manifest.permission.SYSTEM_ALERT_WINDOW, ...) together with any other permission while permissionValue.size > 1.

Common situations: Adding a special permission to an existing runtime permission request; misunderstanding that WRITE_SETTINGS/SYSTEM_ALERT_WINDOW need Settings.canDrawOverlays / isWriteSettingsGranted handling; migrating apps that previously requested everything at once.

Related errors


AI-assisted analysis of permissions-dispatcher/PermissionsDispatcher@74b532bf1f (2026-09-08). Data as JSON: /api/errors/0c1c320d08ec9180. Report an issue: GitHub.