Skip to content
aknWiki

Errors

Four error shapes are in use, and one group of endpoints reports failure inside a 200 response. A caller must handle all five.

Shape Body Used by
General {"error":"<message>"} Sessions, people, notifications, calendar, status
Qualified {"error":"<message>","reason":"<value>"} Approval and account status refusals
OAuth {"error":"<code>"}, sometimes with error_description The /auth/oidc endpoints
HTML page A rendered page, not JSON /auth/bridge errors, and the OIDC callback refusal
Success-shaped 200 with a false flag in the body POST /auth/verify, /location, /calendar

The error message is intended for a developer. It is not stable and must not be matched on. Branch on the status code, and on reason where one is present.

Status Meaning Retry
200 Handled. Check the body before assuming success Not applicable
204 Preflight answered Not applicable
302 Redirect in a browser flow Follow it
400 Request is malformed, or a required field is missing Only after correcting the request
401 Credential absent, invalid or expired After obtaining a new credential
403 Credential is valid, the account may not do this No. Escalate to an administrator
404 No such record, or no such provider No
409 The change conflicts with an existing link No. Resolve the conflict first
429 Rate limit reached on an email code endpoint After the interval stated in the message
500 The request failed inside the service or an upstream Once, then escalate
502 An upstream returned an unusable answer Once, then escalate
503 A dependency is unavailable, or a provider is disabled Yes, with backoff
Status Interpretation Correct handling
401 The service does not know who is calling Sign in again
403 The service knows, and refuses Do not retry. Do not sign the person out
503 with Authorization unavailable The account could not be looked up Retry. Do not sign the person out

A caller that treats every refusal as a sign-in failure loops a person through sign-in indefinitely when their account is pending.

POST /auth/verify answers 200 when the token is valid and the account is not permitted.

reason Meaning
pending The account exists and has not been reviewed
rejected The account has been refused
no_project_access Approved, but without a grant for the requested project
phone_not_linked Returned with 403. The number is on no account

Gated endpoints answer 403 with the same vocabulary in reason.

Code Cause
invalid_client The client is not registered, or the secret does not match
invalid_request A required parameter is missing, or the redirect URI is not registered
unsupported_response_type Anything other than code
unsupported_grant_type Anything other than authorization_code
invalid_grant The code is unknown, expired, already used, bound to another client, or the redirect URI or PKCE verifier does not match
invalid_token The access token is unknown or expired
server_error Token signing failed

An invalid authorise request is answered to the caller. It is never delivered to the requested redirect URI.

The bridge endpoints and the OIDC callback refusal render HTML. A client that sets Accept: application/json still receives HTML. Check the content type before parsing, or branch on the status code alone.

Endpoint Failure presentation
GET /calendar/events {"events":[]} with 200, whether the week is empty or the calendar is unreachable
GET /calendar/upcoming-locations {"locations":[]} with 200
Every /location endpoint 200 with a fallback body. See Location
PATCH /auth/people/:personId 200 with failures listed in firebaseSyncErrors
POST /auth/otp/send for an unknown address {"ok":true} with 200, and no mail sent
POST /auth/zitadel/claims when the lookup fails 200 with the urn:akn: claims absent

None of these raise a status code a caller can trap. Inspect the body.

A browser request from an origin outside the allowlist receives no allow-origin header, so the browser rejects the response before the caller sees it. This presents as a network error, not as a 401 or 403. The request itself reached the service and may have taken effect.