Skip to main content

Error codes

Odudu reports errors in three places: the admin API, the protocol endpoints and the server or command that fails to start. Each has its own vocabulary, listed below.

Admin API problems​

A problem with type about:blank carries no more meaning than its HTTP status and title: detail says what was wrong with this request. Most refusals are of this kind.

These refusals have a type of their own, which a client can switch on:

TypeStatusMeaning
about:blank#audit-query-too-broad400The audit read ran past its five second bound because its filters match too many rows to serve cheaply. Narrow the time range with from and to.
about:blank#builtin-scope-confirmation422A built-in scope is deleted only when the request’s confirm names it again. detail names the scope and how many clients and roles would lose it. Repeat the request with confirm set to the scope name.
about:blank#export-too-large413An audit export or a tenant export would be larger than the cap, and is refused whole rather than cut short. Narrow the audit export with from, to or another filter.
about:blank#flow-duplicate-authenticator400A replacement authentication flow names the same authenticator in two steps. A step is addressed by its authenticator, so a repeat has no unambiguous meaning.
about:blank#flow-empty400A replacement authentication flow has no steps. A tenant with no flow cannot be logged into.
about:blank#flow-no-enabled-step400Every step of a replacement authentication flow is disabled, so nobody could log in.
about:blank#flow-no-first-challenge400No step of a replacement authentication flow would run at the start of a login, when no subject is bound yet.
about:blank#flow-unknown-authenticator400A step of a replacement authentication flow names an authenticator that is not registered. detail lists the ones that are.
about:blank#key-active409The signing key is the active one and cannot be retired. Promote another key first.
about:blank#key-algorithm-needed409Retiring the signing key would leave no key for an algorithm a client still requires for its ID tokens or UserInfo responses. detail names the clients.
about:blank#key-not-retired409Only a retired signing key can be deleted. Retire it first.
about:blank#last-administrator409The write would leave the tenant with no enabled administrator. detail names who would be the last.
about:blank#logout-deliveries-pending409The tenant still has back-channel logout tokens to send, and deleting it would discard them. Wait for them to be delivered.
about:blank#no-email409The subject has no email address to send the message to.
about:blank#no-mail-relay409The tenant has no SMTP relay and the deployment no sender, so the mail would only be logged.
about:blank#not-found404Nothing is served at the path, whichever API or tenant it names. detail is "No resource at this path"; it named the path and the route before. A browser that asks for a page is shown one instead.
about:blank#reset-password-off409The tenant has reset_password_allowed off, so it would refuse the link. Turn the setting on first.
about:blank#service-account409A subject that is a client’s service account is not deleted on its own, since the client would be left with none. detail names the client. Delete the client instead, which deletes its account.
about:blank#sessions-live409Deleting the tenant was refused because sessions are still live. Disable the tenant again to end them and tell their relying parties.
about:blank#sessions-not-ended500The tenant was disabled, but ending its sessions did not finish. Repeat the request to finish it.
about:blank#tenant-enabled409A tenant must be disabled before it is deleted, which ends its sessions and tells their relying parties.

A 400 that names fields carries an errors list; an entry has a code when the refusal has one, such as bidi_control_refused for a bidirectional control character in a typed field. The shape of the problem document is under problem details.

An address nothing serves answers 404 with the type about:blank#not-found, and an unhandled failure 500 (every failure of status 500 or above answers 500). Both are problem documents whose instance is the request id. A browser that asks for a page, outside the admin, console API, health and protocol paths, is shown a branded page instead: the same page for every unknown address, with the request id on the failure page and nothing the request or the failure carried.

OAuth and OpenID Connect errors​

The protocol endpoints answer with the error values RFC 6749, RFC 6750, RFC 7591, RFC 8707 and OpenID Connect Core define. At the authorization endpoint a refusal that can be reported to the client is a redirect carrying error; one that cannot is a page. The token endpoint answers a JSON body. The authorization and token endpoints add an error_description, one plain sentence that is never built from the request. Each code has one fixed sentence, and invalid_grant names no cause. The authorization endpoint adds a few that name the parameter at fault, listed after the table.

CodeAnswered byMeaningerror_description
access_deniedauthorization endpointThe user refused consent, or the sign-in the request was waiting on expired, so the client is sent back without a code.The user did not allow the request.
account_selection_requiredauthorization endpointThe request asked for no interaction (prompt=none) but the user must choose between accounts.The user must choose an account first.
consent_requiredauthorization endpointThe request asked for no interaction (prompt=none) but the user has not consented to what the client asks for.The user has not agreed to this request yet.
insufficient_scopeUserInfo endpointThe access token does not carry the openid scope the UserInfo endpoint requires.
invalid_clientauthorization endpoint, token endpointClient authentication failed: the client is unknown or its credential is wrong.Client authentication failed.
invalid_client_metadataclient registrationA value in the registration request is not acceptable client metadata. error_description names the field.
invalid_granttoken endpointThe authorization code or refresh token is unknown, expired, already used, issued to another client, or does not match the redirect URI or the PKCE verifier. The response never says which, by design.The code or token is not valid.
invalid_redirect_uriclient registrationA redirect URI in the registration request is not one the server accepts.
invalid_requestauthorization endpoint, token endpoint, UserInfo endpointThe request is malformed: a required parameter is missing, repeated or has an unacceptable value.The request is missing a parameter or has a wrong one.
invalid_scopeauthorization endpoint, token endpointA requested scope is unknown, not assigned to the client, or malformed.A requested scope is not available to this client.
invalid_targetauthorization endpoint, token endpointA resource indicator (RFC 8707) is malformed or names an audience the client may not request.A requested resource is not available to this client.
invalid_tokenUserInfo endpoint, client registrationThe access token, or the initial access token of a dynamic registration, is missing, expired, revoked, spent or otherwise not valid for this endpoint. UserInfo answers with 401 and a WWW-Authenticate challenge.
login_requiredauthorization endpointThe request asked for no interaction (prompt=none) but the user is not signed in.The user is not signed in.
request_not_supportedauthorization endpointThe request carried a request object, which this server does not support.The request parameter is not supported.
request_uri_not_supportedauthorization endpointThe request carried a request_uri, which this server does not support.The request_uri parameter is not supported.
unauthorized_clienttoken endpointThe client is not allowed to use the grant type it asked for.This client may not use this grant type.
unsupported_grant_typetoken endpointThe grant_type is not one this server supports.This grant type is not supported.
unsupported_response_typeauthorization endpointThe response_type is not one this server supports.Only response_type=code is supported.

At the authorization endpoint, an invalid_request can say which parameter was wrong:

  • A parameter was sent more than once
  • code_challenge is required
  • code_challenge is not valid
  • code_challenge_method must be S256
  • prompt is not valid
  • prompt=create is not supported: registration is off
  • prompt=create cannot be sent with id_token_hint or a claims sub
  • max_age is not valid
  • claims is not valid
  • id_token_hint is not valid

Server and command errors​

A command or the server that stops with an error prints its code and a message. A command that stops this way exits with a non-zero status.

Startup and configuration​

CodeMeaning
config_invalidThe environment does not describe a valid configuration. The message names every variable at fault, or the production rule that was broken.
module_cycleThe server modules depend on each other in a cycle, so none can start first.
module_duplicateTwo server modules registered under the same name.
module_stop_failedOne or more modules failed while the server was shutting down. The failures are in the cause.
module_unknown_dependencyA server module depends on a module that was not registered.
smtp_destination_refusedThe SMTP relay address is one the server refuses to connect to: a loopback, link-local or multicast address, or a private one while ODUDU_ALLOW_PRIVATE_SMTP_HOSTS is off.
static_tree_too_largeA directory of static files, such as ODUDU_INSTRUMENT_DIR, holds more entries, files or bytes than the server will serve, so it is probably not the build.

Commands​

CodeMeaning
admin_client_list_fullThe built-in admin client already holds as many redirect URIs as a client may, so the console’s address cannot be added.
admin_client_not_builtinA client with the id of the built-in admin client already exists in the tenant but is not it, so the console cannot be registered.
cli_unknown_commandThe first argument of odudu is not a command. The exit status is 2 and the commands are printed.
client_origins_unknown_commandodudu client-origins was given a subcommand it does not have.
console_invalid_optionsThe options of an odudu console command are missing or unusable.
console_unknown_commandodudu console was given a subcommand it does not have.
init_invalid_optionsThe options or environment of odudu init are not usable, for example a public base URL that is not a loopback address.
init_roles_without_secretsodudu init found the service role in the database but not the state file holding its password. Restore the file, or drop the role if the database is disposable.
seed_admin_existsodudu seed admin found a subject with that name already in the system tenant.
seed_conflictThe thing odudu seed was asked to create exists already in a form that disagrees with the request, such as a client of the other type.
seed_invalid_optionsThe options of an odudu seed command are missing, contradictory or have an unacceptable value. The message names them.
seed_not_foundodudu seed was told to act on something that does not exist.
seed_system_tenant_conflictA tenant named like the system tenant exists under another id, so the system tenant cannot be created.
seed_unknown_commandodudu seed was given a subcommand it does not have.
seed_unknown_grant_type--grant-type names a grant type this server does not implement.
seed_unknown_settingA --set names a tenant setting that does not exist. The message lists the ones that do.

Background passes​

CodeMeaning
logout_sender_cannot_enumerate_tenantsThe logout sender must list every tenant, which needs a connection that bypasses row-level security, and ODUDU_DATABASE_URL names a role that does not.
logout_sender_requires_app_database_urlThe logout sender needs ODUDU_APP_DATABASE_URL to claim deliveries under the tenant policy.
logout_sender_serving_role_bypasses_rlsODUDU_APP_DATABASE_URL names a superuser or BYPASSRLS role, so the logout sender would not claim deliveries under the tenant policy.
outbox_cannot_enumerate_tenantsThe mail sender must list every tenant, which needs a connection that bypasses row-level security, and ODUDU_DATABASE_URL names a role that does not.
outbox_requires_app_database_urlThe mail sender needs ODUDU_APP_DATABASE_URL to claim messages under the tenant policy.
outbox_serving_role_bypasses_rlsODUDU_APP_DATABASE_URL names a superuser or BYPASSRLS role, so the mail sender would not claim messages under the tenant policy.
reap_cannot_enumerate_tenantsodudu reap must list every tenant, which needs a connection that bypasses row-level security, and ODUDU_DATABASE_URL names a role that neither is a superuser nor has BYPASSRLS.
reap_requires_app_database_urlodudu reap deletes under the tenant policy and so needs ODUDU_APP_DATABASE_URL; the owner role escapes the policy.
reap_serving_role_bypasses_rlsODUDU_APP_DATABASE_URL names a superuser or BYPASSRLS role, so odudu reap would not delete under the tenant policy.

Signing, tokens and encryption​

CodeMeaning
client_key_invalidThe console client key is not base64-encoded JSON, or is not an EC P-256 key with its public coordinates.
insert_returned_no_rowA signing key insert returned no row, which the database should never do.
jwe_alg_unsupportedAn encrypted response was asked for with a key-management algorithm that is not one of the permitted ones.
jwt_alg_mismatchA token header’s alg is not the algorithm of the key its kid names.
jwt_header_invalidA token has no readable header.
jwt_kid_missingA token header carries no kid, so no key can be chosen to verify it.
jwt_typ_mismatchA token’s typ is one that must not be accepted at this endpoint.
jwt_unknown_keyA token header names a kid that is not one of the tenant’s keys.
kek_invalidThe key-encryption key is not 32 bytes.
signing_key_not_foundThe tenant has no active signing key to sign with.

Data and validation​

CodeMeaning
bidi_control_refusedA typed field holds a bidirectional control character (U+202A to U+202E, U+2066 to U+2069).
claim_mapper_duplicateTwo claim mappers registered under the same name.
client_scope_not_foundThere is no client scope with that id.
credential_not_foundThere is no credential with that id.
group_not_foundThere is no group with that id.
group_reparent_cycleMoving the group under that parent would make it its own ancestor.
invalid_emailAn email address is not well formed.
role_composite_cycleAdding the composite role would make a role contain itself.
role_not_foundA role that was expected to exist does not.
subject_not_foundThere is no subject with that id.
tenant_context_missingA tenant-scoped query was started without a valid tenant id, so it was refused rather than run unscoped.
tenant_not_foundThere is no tenant with that id in the current context.
user_not_foundThere is no user for that subject.