microg/GmsCore · error · IllegalAccessException
DroidGuard should not be available locally
Error message
DroidGuard should not be available locally
What it means
microG's DroidGuard NetworkHandleProxyFactory.createHandle() refuses to build a local guard handle when DroidGuardPreferences.isLocalAvailable(context) is false. Local DroidGuard execution (bytecode from DB or fetched from server, run on-device) is an opt-in/conditional capability; when it is not available the factory throws IllegalAccessException instead of silently downgrading. The same guard exists in createPingHandle() and createLowLatencyHandle().
Source
Thrown at play-services-droidguard/core/src/main/kotlin/org/microg/gms/droidguard/core/NetworkHandleProxyFactory.kt:31
import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest
import okio.ByteString.Companion.decodeHex
import okio.ByteString.Companion.of
import org.microg.gms.droidguard.*
import org.microg.gms.profile.Build
import org.microg.gms.profile.ProfileManager
import org.microg.gms.utils.singleInstanceOf
import java.io.File
import java.util.*
import com.android.volley.Request as VolleyRequest
import com.android.volley.Response as VolleyResponse
class NetworkHandleProxyFactory(private val context: Context) : HandleProxyFactory(context) {
private val dgDb: DgDatabaseHelper = DgDatabaseHelper(context)
private val version = VersionUtil(context)
private val queue = singleInstanceOf { Volley.newRequestQueue(context.applicationContext) }
fun createHandle(packageName: String, flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = readFromDatabase(flow) ?: fetchFromServer(flow, packageName)
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)
}
fun createPingHandle(packageName: String, flow: String, callback: GuardCallback, pingData: PingData?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = fetchFromServer(flow, createRequest(flow, packageName, pingData))
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, DroidGuardResultsRequest().also { it.clientVersion = 0 })
}
fun createLowLatencyHandle(flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy {
if (!DroidGuardPreferences.isLocalAvailable(context)) throw IllegalAccessException("DroidGuard should not be available locally")
val (vmKey, byteCode, bytes) = readFromDatabase("fast") ?: throw Exception("low latency (fast) flow not available")
return createHandleProxy(flow, vmKey, byteCode, bytes, callback, request)
}
fun SignedResponse.unpack(): Response {
if (SignatureVerifier.verifySignature(data_!!.toByteArray(), signature!!.toByteArray())) {View on GitHub (pinned to 157c9d86ac)
Solutions
- Enable local DroidGuard execution in the microG settings app (DroidGuard section) and retry
- Verify DroidGuardPreferences.isLocalAvailable(context) before calling createHandle and route to a remote handle (RemoteHandleImpl with a configured network server URL) as a fallback
- Update microG to a version that supports local DroidGuard on your device fingerprint
- Catch IllegalAccessException around handle creation and surface a 'local DroidGuard unavailable' state to the caller
Example fix
// before
val handle = factory.createHandle(packageName, flow, callback, request)
// after
if (DroidGuardPreferences.isLocalAvailable(context)) {
val handle = factory.createHandle(packageName, flow, callback, request)
} else {
val handle = RemoteHandleImpl(context, packageName).also { it.init(flow) }
} Defensive patterns
Strategy: validation
Validate before calling
if (!DroidGuardPreferences.isLocalAvailable(context)) {
// fall back to remote handle or disable feature
} else {
val handle = factory.createHandle(packageName, flow, callback, request)
} Try / catch
try {
factory.createHandle(packageName, flow, callback, request)
} catch (e: IllegalAccessException) {
switchToRemoteHandle(context, packageName, flow)
} Prevention
- Always gate DroidGuard local calls on DroidGuardPreferences.isLocalAvailable(context)
- Keep local execution enabled in microG settings for deployments that require it
- Design flows with a remote-handle fallback path
When it happens
Trigger: Calling createHandle(packageName, flow, callback, request) on a device where DroidGuardPreferences.isLocalAvailable(context) returns false — i.e. local DroidGuard execution is disabled in microG settings or the device/build is not provisioned for local execution.
Common situations: User has not enabled 'DroidGuard local execution' in microG settings; a custom ROM or unsupported Build.FINGERPRINT lacks local DroidGuard support; an app integrates the DroidGuard API assuming local handling while the install is remote-only.
Related errors
- Network URL required
- Signature invalid
- Access denied, missing google package permission for
- Required caller information missing
- ERROR_MISSING_INSTANCEID_SERVICE
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/54fcf43f85657f1b.
Report an issue: GitHub.