Mr.AndroidShin / Dev Tools

Debugging log · Permissions

"SecurityException: Permission Denial" at runtime

I added the permission to the manifest, ran the app, called the API — and it crashed with SecurityException: Permission Denial. My first reaction was "but I declared it!" And that's the exact misunderstanding the modern permission model is built around: for sensitive permissions, declaring is only half the job. The user has to actually grant it, at runtime, and until they do, the call fails.

The short version: since Android 6 (API 23), "dangerous" permissions need two things — a manifest declaration and a runtime grant from the user. Declaring alone isn't enough. Check at call time, request if needed, and only act once granted.

The error

java.lang.SecurityException: Permission Denial: ...
requires android.permission.CAMERA

Two kinds of permission

Android splits permissions into two groups. Normal permissions (internet access, for example) are granted automatically just by declaring them in the manifest. Dangerous permissions — camera, location, microphone, contacts, and others that touch private data or hardware — require the user's explicit consent at runtime. The manifest line is still required, but it only makes the permission requestable; it doesn't grant it. Call a protected API without the runtime grant and you get this SecurityException.

The fix — declare, check, request, then act

1. Declare it in the manifest

<uses-permission android:name="android.permission.CAMERA" />

2. Check before you use it

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
        == PackageManager.PERMISSION_GRANTED) {
    openCamera()           // already granted
} else {
    requestCameraLauncher.launch(Manifest.permission.CAMERA)
}

3. Request it, and react to the result

val requestCameraLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { granted ->
    if (granted) openCamera()
    else showWhyWeNeedIt()   // handle denial gracefully
}

The key discipline: never assume the permission is held. Check at the moment you need it, request if it isn't, and run the protected code only from the "granted" path.

Things that cause this even when you "did it right"

Handle denial as a real path, not an afterthought. If the user says no, the app shouldn't crash or loop the dialog — explain what the feature needs and let them continue without it, or send them to Settings if they want to enable it later.

Permission names above use the camera as an example — the same pattern applies to any dangerous permission.