Skip to main content

Errors

LumoAuth uses standard HTTP response codes and returns error bodies in a consistent format across all APIs.

HTTP Status Codes

CodeMeaningAction
200 OKRequest succeeded.
201 CreatedResource was created.
204 No ContentSucceeded with no response body (common for DELETE).
400 Bad RequestMalformed request or invalid parameters.Fix the request
401 UnauthorizedMissing or invalid credentials/token.Refresh token or re-authenticate
403 ForbiddenAuthenticated but not authorized.Check scopes and permissions
404 Not FoundResource does not exist.Check the endpoint URL and org ID
409 ConflictResource already exists (e.g. duplicate email).Read or update instead of create
422 Unprocessable EntityValidation errors on the submitted data.See details field
429 Too Many RequestsRate limit exceeded.Back off — check Retry-After header
500 Internal Server ErrorUnexpected server error.Retry with exponential backoff
503 Service UnavailableTemporarily unavailable (maintenance, overload).Retry later

Error Response Format

Generic API Error
{
"error": "validation_error",
"message": "Validation failed",
"status": 400,
"details": {
"email": "Invalid email format",
"password": "Must be at least 8 characters"
}
}
OAuth Error (RFC 6749)
{
"error": "invalid_client",
"error_description": "Client authentication failed: unknown client_id",
"error_uri": "https://docs.lumoauth.dev/errors#invalid_client"
}

Common API Error Codes

errorStatusDescription
validation_error400 / 422One or more request fields failed validation. See details.
invalid_request400Missing or malformed request parameter.
invalid_client401OAuth client authentication failed.
invalid_token401Access token is missing, expired, or invalid.
unauthorized401No credentials provided.
access_denied403Authenticated but insufficient privileges.
insufficient_scope403Token scope does not cover this resource.
not_found404Resource does not exist.
conflict409Resource already exists.
rate_limit_exceeded429Too many requests. Retry after Retry-After seconds.
server_error500Unexpected internal error.
temporarily_unavailable503Service temporarily unavailable.

OAuth 2.0 Errors (RFC 6749)

Returned by the authorization, token, and introspection endpoints. RFC 6749 — OAuth 2.0 Authorization Framework defines the core OAuth protocol (authorize and token endpoints, grant types, and the error body shape shown below).

errorStatusCommon cause
invalid_request400Missing grant_type, invalid JSON body, unsupported content type
invalid_client401Wrong client_id, wrong client_secret, client not in organization
invalid_grant400Authorization code expired or reused, refresh token revoked
unauthorized_client401Client is not authorized for this grant type
unsupported_grant_type400Grant type typo or not enabled
invalid_scope400Scope not registered or exceeds client's allowed scopes
access_denied403User denied consent, or policy blocked the request
server_error500Internal server error
temporarily_unavailable503Maintenance or overload

Authorization API Errors

errorStatusDescription
MISSING_PERMISSION400Required field permission is missing
INVALID_PERMISSIONS400permissions must be a non-empty array
MISSING_FIELDS400Zanzibar check missing object, relation, or user
CHECK_FAILED500Permission check failed due to server error
ZANZIBAR_CHECK_FAILED400Invalid tuple format or unknown namespace
LIST_FAILED500Failed to retrieve user permissions

Agent & Token Exchange Errors

errorStatusDescription
invalid_target400Token exchange target (audience) is invalid
unsupported_token_type400subject_token_type or actor_token_type not supported
delegation_not_allowed403Client is not configured to allow token exchange
budget_exceeded429Agent has exceeded its configured budget limits
capability_denied403Agent lacks the required capability
workload_identity_failed401Failed to verify workload identity token

Dynamic Client Registration Errors

errorStatusDescription
invalid_redirect_uri400One or more redirect URIs use a non-allowed scheme
registration_not_allowed403Dynamic registration is disabled for this organization
invalid_client_metadata400Client metadata is invalid or unsupported

Validation Errors

When a validation_error is returned, the details object maps each invalid field to a human-readable message:

422 Validation Error
{
"error": "validation_error",
"message": "Validation failed",
"status": 422,
"details": {
"name": "Name is required",
"redirectUris[0]": "Must be a valid HTTPS URL"
}
}

Rate Limit Errors

429 Rate Limit Exceeded
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 30 seconds.",
"status": 429,
"retryAfter": 30
}

The response also includes the Retry-After HTTP header with the number of seconds to wait.

Error-handling example

import requests, time

class LumoAuthClient:
MAX_RETRIES = 3

def call_api(self, method, url, **kwargs):
for attempt in range(self.MAX_RETRIES):
response = requests.request(method, url, **kwargs)
if response.ok:
return response.json()
if response.status_code == 401:
self.refresh_token()
continue
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", 60)))
continue
if response.status_code >= 500:
time.sleep(2 ** attempt)
continue
err = response.json()
raise LumoAuthError(code=err.get("error"), message=err.get("message") or err.get("error_description"))
raise LumoAuthError(code="max_retries", message="Max retries exceeded")