{"record":{"id":"a28433460828376d","repo":"microg/GmsCore","slug":"invalid-state-err","errorCode":"INVALID_STATE_ERR","errorMessage":"null","messagePattern":"null","errorType":"error_code","errorClass":"RequestHandlingException","httpStatus":null,"severity":"error","filePath":"play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockTransportHandler.kt","lineNumber":85,"sourceCode":"                .setNegativeButtonText(activity.getString(android.R.string.cancel))\n                .build()\n            invokeStatusChanged(TransportHandlerCallback.STATUS_WAITING_FOR_USER)\n            if (signature != null) {\n                prompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(signature))\n            } else {\n                prompt.authenticate(promptInfo)\n            }\n            continuation.invokeOnCancellation { prompt.cancelAuthentication() }\n        }\n    }\n\n    suspend fun getActiveSignature(\n        options: RequestOptions,\n        callingPackage: String,\n        keyId: ByteArray\n    ): Signature {\n        val signature =\n            store.getSignature(options.rpId, keyId) ?: throw RequestHandlingException(ErrorCode.INVALID_STATE_ERR)\n        showBiometricPrompt(getApplicationName(activity, options, callingPackage), signature)\n        return signature\n    }\n\n    fun getCredentialData(aaguid: ByteArray, credentialId: CredentialId, coseKey: CoseKey) = AttestedCredentialData(\n        aaguid,\n        credentialId.encode(),\n        coseKey.encode()\n    )\n\n    fun getAuthenticatorData(\n        rpId: String,\n        credentialData: AttestedCredentialData?,\n        userPresent: Boolean = true,\n        userVerified: Boolean = true,\n        signCount: Int = 0\n    ) = AuthenticatorData(\n        rpId.toByteArray().digest(\"SHA-256\"),","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/microg/GmsCore/blob/157c9d86ac46c195a86c2f15ab55c84036223f95/play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/transport/screenlock/ScreenLockTransportHandler.kt#L67-L103","documentation":"ScreenLockTransportHandler.getActiveSignature looks up the requested credential (by rpId and keyId) in the local key store and throws RequestHandlingException(ErrorCode.INVALID_STATE_ERR) when it does not exist. This means the caller asked to sign with a credential ID the screen-lock transport has no record of. It usually indicates stale or inconsistent state between the relying party's stored credentials and the device keystore/database.","triggerScenarios":"register() or sign() resolves a keyId and calls getActiveSignature, but store.getSignature(options.rpId, keyId) returns null because the key was deleted, the rpId mismatches, or the credential id came from another device/transport.","commonSituations":"KeyStore entry cleared (device wipe, app data clear) while the RP still holds the old credential ID; server-side allowList references credentials registered on another device; rpId mismatch after a domain change.","solutions":["Catch RequestHandlingException with ErrorCode.INVALID_STATE_ERR and fall back to a fresh registration flow so a new credential is created.","Remove the stale credential ID from the RP's allowList and re-register the authenticator.","Verify rpId exactly matches the origin used at registration and that the credential was created via this transport on this device."],"exampleFix":"// before\nval signature = screenLockHandler.getActiveSignature(options, pkg, keyId)\n// after\nval signature = try {\n    screenLockHandler.getActiveSignature(options, pkg, keyId)\n} catch (e: RequestHandlingException) {\n    if (e.errorCode == ErrorCode.INVALID_STATE_ERR) registerNewCredential(options)\n    else throw e\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    screenLockHandler.getActiveSignature(options, pkg, keyId)\n} catch (e: RequestHandlingException) {\n    if (e.errorCode == ErrorCode.INVALID_STATE_ERR) fallBackToRegistration()\n    else throw e\n}","preventionTips":["Verify the credential id exists locally before asserting","Keep the RP server's credential list in sync with device registrations","Confirm rpId matches the registration origin exactly"],"tags":["fido","webauthn","android","screen-lock","keystore"],"backgroundTag":"resource-not-found","analyzedSha":"157c9d86ac46c195a86c2f15ab55c84036223f95","analyzedAt":"2026-09-06T17:27:33.892Z","contentChangedAt":"2026-09-06T17:27:33.892Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}