Documentation
TroubleshootingError handlingException codes

Exception codes

Every code a service actually returns, grouped by scope and by what you do about it.

error.code is the stable, machine-readable half of a failure. Message text changes with translations and copy edits; the code does not.

Codes are scoped per service. Each one below is listed under the service that produces it, and only codes that are actually in use appear here.

The same string can exist in more than one source. rate_limit_exceeded from the gateway and rate_limit_exceeded from authentication are separate definitions that happen to agree — match on code and on which call you made.

From the SDK

Produced locally, without a round trip.

no_session401

A call needing a session ran with none stored.

request_timeout408

Your configured timeout elapsed.

network_error0

Nothing answered. This is the offline case.

invalid_path400

A path parameter was . or ... Ids are URL-encoded into a single segment, but those two would still resolve to another endpoint, so the call is refused.

unknown_error

A response arrived that did not parse as an error.

Gateway

Every call to a project goes through the gateway at https://<project>.nulvless.co first. It checks the API key and the state of the project before the request reaches a service, so these codes can come back from any SDK call.

project_unavailable403

The project is in a state that cannot serve requests.

rate_limit_exceeded429

Too many requests from your IP. The Retry-After header says when to try again. An IP that keeps hitting routes that do not exist is blocked for ten minutes.

internal_error500

The gateway failed while handling the request.

service_not_enabled501

The service is not installed in this project, or not in this environment.

bad_gateway502

The service behind the gateway could not be reached.

service_unavailable503

The service failed to set up for this environment.

project_not_ready503

The project is still being built or restored. Retry shortly.

upstream_timeout504

The service took too long to start answering.

idle_timeout504

The service stopped sending data mid-response.

deadline_exceeded504

The request ran past the total time allowed for the route.

project_paused540

The project is paused. Resume it in the dashboard.

A route the gateway does not know answers 404 with an empty body, so there is no code to read.

Authentication

The largest scope: sign-up, sign-in, sessions, factors, grants, OAuth.

Not signed in — 401

unauthorized401

No valid session token.

invalid_credentials401

The password, code or token did not match.

refresh_token_not_found401

The refresh token matches no session. Sign the user in again.

refresh_token_already_used401

The refresh token was already exchanged and was replayed after the reuse window. The whole session is ended as a precaution. Sign the user in again.

refresh_token_not_issued_here401

The refresh token is newer than the session knows about, so it was not issued by this environment. Sign the user in again rather than retrying.

Signed in, but blocked — 403

protected_action_denied403

Sudo mode is required for this action.

mfa_required403

The environment requires MFA and this session never used a second factor.

mfa_factors_limit_reached403

The user already holds the most authenticator apps and SMS factors the environment allows. Remove one before adding another.

mfa_phone_already_enrolled409

This phone is already one of the user's SMS factors.

mfa_phone_not_supported400

phone was sent while enrolling a factor other than sms_otp.

registration_closed403

Sign-up is turned off for this environment.

user_not_confirmed403

The account was never confirmed.

user_banned403

The account is banned.

forbidden_resource_access403

No grant on the resource, or a required scope or role is missing.

forbidden_access_waiting_accept403

A grant exists but is still invited or requested.

forbidden_special_role_required403

The action needs a specific role.

cannot_leave_owner_access403

An owner cannot leave their own resource.

oauth_account_link_required403

The provider account must be linked to an existing user first.

unavailable403

The method is disabled for this environment.

action_verification_failed403 / 401

A challenge could not be confirmed — wrong code, or too many attempts.

not_allowed403 / 401 / 422

A general refusal. Read the message.

Rejected input — 400

password_weak400

Failed the length or character requirements.

password_leaked400

Found in a known breach, and the environment blocks those.

captcha_required400

A captcha token was expected and not sent.

captcha_verification_failed400

The captcha token was rejected.

bad_oauth_state400

The OAuth state did not match.

bad_oauth_callback400

The provider callback was malformed.

redirect_uri_mismatch400

The redirect URI is not on the allowlist.

provider_unavailable400

The social provider is off for this environment.

provider_unsupported_method400

That provider does not support the requested method.

oauth_email_missing400

The provider returned no email.

oauth_email_not_verified400

The provider returned an unverified email.

Conflicts with existing data — 422

email_already_exists422

Taken.

phone_already_exists422

Taken.

username_already_exists422

Taken.

user_missing_email422

The environment requires an email and none was given.

user_missing_phone422

The environment requires a phone and none was given.

user_already_confirmed422

Confirming something already confirmed.

user_already_banned422

Banning someone already banned.

user_not_banned422

Unbanning someone who is not banned.

permission_already_granted422

The grant already exists.

Sign-up can return several of these at once — message becomes an array.

Not now

rate_limit_exceeded429

Too many attempts. The body carries a retryAfter the SDK does not surface.

Edge function runtime

A different scope from the platform API. These are produced by the runtime that actually executes your function, not by the API that deploys it — so you see the first group as an HTTP response to an invocation, and the second only in logs.

Returned by an invocation

function_not_found404

No function at that path.

function_unavailable403

The function exists but the control plane refuses to serve it — deactivated, or its project is not servable. A settled state, not a transient one.

execution_timeout546

Wall-clock limit exceeded.

cpu_time_limit_exceeded546

CPU time limit exceeded — the function was busy rather than waiting.

memory_limit_exceeded546

Memory limit exceeded.

resource_unavailable503

The function could not be loaded — metadata or bundle download failed. Retryable.

boot_failed503

The worker could not be started. Retryable.

546 is not a typo

The three limit violations answer with 546, a non-standard status chosen so they are distinguishable from anything your own code returns. Match on it directly — a generic status >= 500 check will lump them in with real server errors.

When your own code throws, the runtime answers a plain 500 with no code field at all. That absence is the signal: a coded failure came from the platform, an uncoded 500 came from your function.

Recorded in logs

The runtime ships events to the logging service rather than to the caller. Four carry an error.code, and they mirror the limit violations above — so a 546 your users saw has a matching log line with the limit that was hit:

internal_server_error

An unhandled error inside the function.

memory_limit_exceeded

Carries runtime.memory_limit_mb.

execution_timeout

Carries runtime.timeout_ms.

cpu_time_limit_exceeded

Carries runtime.cpu_time_limit_ms.

Every runtime log also carries a kind, which is how you filter them apart: log for your own console.* output, boot for a cold start (with cold_start_ms), invoked for per-request CPU and memory, shutdown for a worker ending, and one per limit violation.

A shutdown carries a reason. memory_limit_exceeded and cpu_hard_limit_exceeded are logged as errors, cpu_soft_limit_reached as a warning, and the routine ones — inactivity, lifetime recycle — as info.

Only kind: "log" is your function's own output. Everything else is platform-generated and marked internal, which is what keeps runtime bookkeeping out of your log consumption metrics.

Notifications

Sending email and SMS, and the templates behind them.

unauthorized_platform401

Bad or missing key.

rate_limit_exceeded429

The send quota for this channel is spent. No retryAfter on this one.

comms.email.send resolving without an error means the message was accepted for delivery, not delivered. Everything after that point shows up on the record, not on the call.

Next

On this page