microg/GmsCore · error · RuntimeException
No result
Error message
No result
What it means
In HybridAuthenticateActivity.handleMakeCredential, the activity waits for a nested authenticator activity via suspendCancellableCoroutine; if the launched Intent result carries no FIDO2_KEY_CREDENTIAL_EXTRA byte array, it throws RuntimeException("No result"). The inner activity returned without producing a credential (typically cancelled or failed).
Source
Thrown at play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/ui/hybrid/HybridAuthenticateActivity.kt:175
.setExcludeList(request.excludeList)
.build()
val browserOptions = BrowserPublicKeyCredentialCreationOptions.Builder()
.setPublicKeyCredentialCreationOptions(publicKeyCredentialCreationOptions)
.setOrigin("https://${request.rp.id}".toUri())
.setClientDataHash(request.clientDataHash).build()
val intent = Intent(this, AuthenticatorActivity::class.java)
.putExtra(AuthenticatorActivity.KEY_SOURCE, AuthenticatorActivity.SOURCE_HYBRID)
.putExtra(AuthenticatorActivity.KEY_TYPE, AuthenticatorActivity.TYPE_REGISTER)
.putExtra(AuthenticatorActivity.KEY_OPTIONS, browserOptions.serializeToBytes())
val result = suspendCancellableCoroutine { continuation ->
waitingLauncherContinuation = continuation
waitingLauncher.launch(intent)
}
val resultBytes = result.data?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA) ?: throw RuntimeException("No result")
val publicKeyCredential = PublicKeyCredential.deserializeFromBytes(resultBytes)
val response = publicKeyCredential.response as? AuthenticatorAttestationResponse? ?: throw RuntimeException("Invalid result")
val attestationObject = AttestationObject.decode(response.attestationObject)
return AuthenticatorMakeCredentialResponse(
authData = attestationObject.authData,
fmt = attestationObject.fmt,
attStmt = attestationObject.attStmt
)
}
private suspend fun handleGetAssertion(request: AuthenticatorGetAssertionRequest): AuthenticatorGetAssertionResponse {
val publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions.Builder()
.setRpId(request.rpId)
.setChallenge(request.clientDataHash)
.setAllowList(request.allowList)
.setRequireUserVerification(request.options?.userVerification?.takeIf { it }?.let { UserVerificationRequirement.REQUIRED })
.build()View on GitHub (pinned to 157c9d86ac)
Solutions
- Check resultCode for RESULT_OK/RESULT_CANCELED before reading the credential extra
- Show a cancellation message and re-launch the flow if the user cancelled
- Inspect logs of the nested AuthenticatorActivity for failures that end without setting FIDO2_KEY_CREDENTIAL_EXTRA
- Catch the RuntimeException in startHybridConnectionFlow and return a cancelable error to the FIDO client
Example fix
// before
val resultBytes = result.data?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA) ?: throw RuntimeException("No result")
// after
if (resultCode != RESULT_OK) throw UserCanceledException()
val resultBytes = result.data?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA)
?: throw RuntimeException("No result") Defensive patterns
Strategy: validation
Validate before calling
val resultBytes = result.data?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA) if (result == null || resultBytes == null) return null // treat as user-cancel
Type guard
fun Intent?.hasCredentialExtra(): Boolean =
this?.getByteArrayExtra(FIDO2_KEY_CREDENTIAL_EXTRA) != null Try / catch
try {
val response = handleMakeCredential()
} catch (e: RuntimeException) {
if (e.message == "No result") emit(FidoResult.Canceled) else throw e
} Prevention
- Check resultCode == RESULT_OK before reading extras
- Treat missing extras as user cancellation, not a crash
- Log inner-activity failures that finish without a credential
- Keep the hybrid flow foregrounded so the nested activity is not killed
When it happens
Trigger: waitingLauncher.launch(intent) returns a result Intent whose data is null or lacks the FIDO2_KEY_CREDENTIAL_EXTRA extra — i.e. the invoked AuthenticatorActivity finished with RESULT_CANCELED or without a credential payload.
Common situations: User cancelled the hybrid (caBLE/QR) sign-up flow; the inner activity crashed or timed out; the wrong response code path returned a bare result Intent.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- Transport ${transport} not supported
- Attachment ${attachment} not supported
- Attestation conveyance preference ${attachment} not supporte
- No response set.
- PublicKeyCredentialType ${type} not supported
AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06).
Data as JSON: /api/errors/fcd8c29f2ad4046b.
Report an issue: GitHub.