permissions-dispatcher/PermissionsDispatcher · error · SpecialPermissionsWithNeverAskAgainException

'@NeverAskAgain' annotated method never being called with 'W

Error message

'@NeverAskAgain' annotated method never being called with 'WRITE_SETTINGS' or 'SYSTEM_ALERT_WINDOW' permission.

What it means

PermissionsDispatcher throws this at compile time when a method annotated with @OnNeverAskAgain includes WRITE_SETTINGS or SYSTEM_ALERT_WINDOW in its permission list. These special permissions are granted through Settings screens rather than the runtime dialog, so the runtime 'never ask again' callback can never fire for them; the annotation is meaningless and flagged as an error.

Source

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

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 ->
        items.firstOrNull { it != item && it.simpleName == item.simpleName }?.let {
            throw DuplicatedMethodNameException(item)
        }
    }
}

View on GitHub (pinned to 74b532bf1f)

Solutions

  1. Remove WRITE_SETTINGS and SYSTEM_ALERT_WINDOW from the @NeverAskAgain method's permission list
  2. Handle special-permission 'denied' states manually by checking Settings.canDrawOverlays() or Settings.System.canWrite() and directing the user to the Settings screen
  3. Keep a separate @NeedsPermission method for the special permission with only @OnShowRationale/@OnPermissionDenied handling, no @NeverAskAgain

Example fix

// before
@NeverAskAgain(Manifest.permission.CAMERA, Manifest.permission.WRITE_SETTINGS)
fun onCameraNeverAskAgain() { }

// after
@NeverAskAgain(Manifest.permission.CAMERA)
fun onCameraNeverAskAgain() { }
Defensive patterns

Strategy: validation

Validate before calling

val specialPerms = setOf(Manifest.permission.WRITE_SETTINGS, Manifest.permission.SYSTEM_ALERT_WINDOW)
// ensure @NeverAskAgain callback lists never include special permissions
val neverAskAgainPerms: Array<String> = callbackPermissions
require(neverAskAgainPerms.none { it in specialPerms }) {
    "@NeverAskAgain cannot be used with WRITE_SETTINGS or SYSTEM_ALERT_WINDOW"
}

Type guard

fun isSpecialPermission(p: String) =
    p == Manifest.permission.WRITE_SETTINGS || p == Manifest.permission.SYSTEM_ALERT_WINDOW

val Array<String>.containsSpecial: Boolean get() = any { isSpecialPermission(it) }

Prevention

When it happens

Trigger: Annotating a callback method with @NeverAskAgain and listing Manifest.permission.WRITE_SETTINGS or Manifest.permission.SYSTEM_ALERT_WINDOW among its permissions, then running the annotation processor (Kotlin kapt / Java APT build).

Common situations: Developers mirror the same permission array across @NeedsPermission/@OnNeverAskAgain/@OnPermissionDenied callbacks, accidentally carrying WRITE_SETTINGS or SYSTEM_ALERT_WINDOW into the @NeverAskAgain method.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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