microg/GmsCore · error · RequestHandlingException

DATA_ERR

DATA_ERR

Error message

The request options are not valid

What it means

The RequestOptions.registerOptions extension unwraps a WebAuthn/FIDO registration request into PublicKeyCredentialCreationOptions. It only accepts BrowserPublicKeyCredentialCreationOptions (unwrapping its inner options) or a plain PublicKeyCredentialCreationOptions; anything else throws RequestHandlingException with code DATA_ERR and message 'The request options are not valid'. This rejects mismatched option types (e.g. a sign/get request passed where a create/register request is expected).

Source

Thrown at play-services-fido/core/src/main/kotlin/org/microg/gms/fido/core/RequestHandling.kt:42

import org.microg.gms.fido.core.transport.Transport
import org.microg.gms.utils.*
import java.net.HttpURLConnection
import java.security.MessageDigest

private const val TAG = "Fido"

class RequestHandlingException(val errorCode: ErrorCode, message: String? = null) : Exception(message)
class MissingPinException(message: String? = null): Exception(message)
class WrongPinException(message: String? = null): Exception(message)

data class CredentialUserInfo(val credential: String, val userJson: String, val transport: Transport, val timestamp: Long)
enum class RequestOptionsType { REGISTER, SIGN }

val RequestOptions.registerOptions: PublicKeyCredentialCreationOptions
    get() = when (this) {
        is BrowserPublicKeyCredentialCreationOptions -> publicKeyCredentialCreationOptions
        is PublicKeyCredentialCreationOptions -> this
        else -> throw RequestHandlingException(DATA_ERR, "The request options are not valid")
    }

val RequestOptions.signOptions: PublicKeyCredentialRequestOptions
    get() = when (this) {
        is BrowserPublicKeyCredentialRequestOptions -> publicKeyCredentialRequestOptions
        is PublicKeyCredentialRequestOptions -> this
        else -> throw RequestHandlingException(DATA_ERR, "The request options are not valid")
    }

val RequestOptions.type: RequestOptionsType
    get() = when (this) {
        is PublicKeyCredentialCreationOptions, is BrowserPublicKeyCredentialCreationOptions -> REGISTER
        is PublicKeyCredentialRequestOptions, is BrowserPublicKeyCredentialRequestOptions -> SIGN
        else -> throw RequestHandlingException(INVALID_STATE_ERR)
    }

val RequestOptions.webAuthnType: String
    get() = when (type) {

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Pass PublicKeyCredentialCreationOptions or BrowserPublicKeyCredentialCreationOptions to the registration API
  2. Inspect the actual runtime class of the RequestOptions before use (options is PublicKeyCredentialCreationOptions) and route register vs sign accordingly
  3. If options come from an intent/JSON payload, fix deserialization so registration requests map to the creation-options class
  4. Catch RequestHandlingException and map DATA_ERR to a clear client error explaining the options type was wrong

Example fix

// before
val creation = options.registerOptions // throws DATA_ERR if options is a sign request

// after
val creation = when (options) {
    is BrowserPublicKeyCredentialCreationOptions -> options.publicKeyCredentialCreationOptions
    is PublicKeyCredentialCreationOptions -> options
    else -> return Result.failure(RequestHandlingException(DATA_ERR, "Expected registration options"))
}
Defensive patterns

Strategy: type-guard

Validate before calling

when (options) {
    is BrowserPublicKeyCredentialCreationOptions, is PublicKeyCredentialCreationOptions -> handleRegister(options)
    else -> failWith(DATA_ERR, "registration options required")
}

Type guard

fun RequestOptions.isRegistrationOptions(): Boolean =
    this is BrowserPublicKeyCredentialCreationOptions || this is PublicKeyCredentialCreationOptions

Try / catch

try {
    val creation = options.registerOptions
} catch (e: RequestHandlingException) {
    if (e.code == DATA_ERR) return badRequest("expected registration options")
    throw e
}

Prevention

When it happens

Trigger: Passing a PublicKeyCredentialRequestOptions, BrowserPublicKeyCredentialRequestOptions, or any other RequestOptions subtype to code that reads .registerOptions (the FIDO register/create pipeline).

Common situations: Client code confusing the two WebAuthn ceremonies — calling navigator.credentials.get() options through the register path or vice versa; deserializing option bundles into the wrong class; third-party intents whose extras do not parse into either registration options class.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/2fdead9ee6bcbfd7. Report an issue: GitHub.