microg/GmsCore · error · RuntimeException
Lack of permission
Error message
Lack of permission
What it means
LocationRequestManager.LocationRequestHolder's init/update path throws RuntimeException('Lack of permission') when the app-op check for the request's effective granularity fails — the client does not hold the app-op (runtime appop mode denied) required for the granularity (e.g. precise/coarse) it requested. Unlike SecurityException paths, this surfaces as a RuntimeException inside request registration.
Source
Thrown at play-services-location/core/src/main/kotlin/org/microg/gms/location/manager/LocationRequestManager.kt:436
get() = request.intervalMillis
val updatesPending: Int
get() = request.maxUpdates - updates
val timePendingMillis: Long
get() = request.durationMillis - (SystemClock.elapsedRealtime() - start)
var workSource: WorkSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
private set
val effectiveHighPower: Boolean
get() = request.intervalMillis < 60000 || effectivePriority == PRIORITY_HIGH_ACCURACY
fun update(callback: ILocationCallback, request: LocationRequest): LocationRequestHolder {
val changedGranularity = request.granularity != this.request.granularity || request.granularity == GRANULARITY_PERMISSION_LEVEL
this.callback = callback
this.request = request
this.start = SystemClock.elapsedRealtime()
this.updates = 0
this.workSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
if (changedGranularity) {
if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException("Lack of permission")
}
return this
}
fun start(): LocationRequestHolder {
if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException("Lack of permission")
return this
}
fun cancel() {
try {
callback?.cancel()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
fun check() {View on GitHub (pinned to 157c9d86ac)
Solutions
- Re-grant the location permission/app-op: Settings > Apps > Permissions > Location, or adb shell appops set <pkg> ACCESS_FINE_LOCATION allow.
- Lower the requested granularity (use COARSE granularity) to match the permission actually held.
- Before requesting updates, verify checkSelfPermission and the corresponding app-op mode for fine location.
Example fix
// before
request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000).build() // needs fine app-op
// after
// use coarse when only coarse is granted
request = LocationRequest.Builder(Priority.PRIORITY_BALANCED_POWER_ACCURACY, 1000)
.setGranularity(Granularity.GRANULARITY_COARSE)
.build() Defensive patterns
Strategy: validation
Validate before calling
val fine = ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED val coarse = ContextCompat.checkSelfPermission(context, ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED val granularity = if (fine) Granularity.GRANULARITY_FINE else if (coarse) Granularity.GRANULARITY_COARSE else return
Type guard
fun granularityAllowed(ctx: Context, want: Int): Boolean =
when (want) {
Granularity.GRANULARITY_FINE -> ctx.checkSelfPermission(ACCESS_FINE_LOCATION) == PERMISSION_GRANTED
Granularity.GRANULARITY_COARSE -> ctx.checkSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
else -> true
} Try / catch
try {
client.requestLocationUpdates(request, listener, looper)
} catch (e: RuntimeException) {
if (e.message == "Lack of permission") {
downgradeToCoarseRequest(); promptForPermission()
}
} Prevention
- Match request granularity to actually granted permissions at call time
- Re-check permissions on every onResume before requesting updates
- Avoid adb appops deny on packages that actively use location
When it happens
Trigger: Registering a location request (holder construction after changedGranularity) when checkAppOpForEffectiveGranularity returns false — e.g. the app has ACCESS_FINE_LOCATION declared but the system app-op for fine location is denied, or the request granularity exceeds what the app-op allows.
Common situations: User revoked location via AppOps (adb shell appops set <pkg> FINE_LOCATION deny) while the app keeps requesting; ROMs where runtime grant and app-op state diverge; microG self-check mismatch after permission upgrades.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- Caller must hold $permission for location bypass
- $packageName does not have any of $permissions
- app op denied
- invalid radius:
- invalid latitude:
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/45ef8f3bfcf03f75.
Report an issue: GitHub.