Skip to content
Torii docs

Error codes

Every displayable failure in the SDK is reported as one stable ToriiError object: the sign-in / sign-up callbacks, profile updates, and the data hooks’ error fields all share it. The SDK fills in a sensible message; you branch on the machine-readable code to drive your own side effects (analytics, redirects, a custom banner).

interface ToriiError {
code: ToriiErrorCode;
message: string; // sensible default text; localize your own copy keyed on code
status?: number; // HTTP status, when the failure came from an API response
details?: unknown; // raw problem body or original error, for diagnostics
}
SurfaceProp / field
<SignIn> / <LoginForm>onLoginError(error)
<SignUp> / <SignupForm>onSignupError(error)
<UserProfile> / <UserDashboard>onUpdateError(error)
<ToriiProvider>events.onError(error), session-refresh / sign-out failures
useSessions, useIdentities, useEmailAddresses, useUserProfile, useDataRequest, useDeleteAccount.error
updateProfile / requestDeletionresult.error (when !result.ok)
<SignIn
onLoginError={(error) => {
if (error.code === 'account_banned') analytics.track('blocked_signin');
// error.message is a sensible default, render it directly if you want.
}}
/>

The one exception: the runtime-load failure on useRuntimeStatus() stays a raw Error. It’s a CDN/loader infrastructure failure, not an API error.

ToriiErrorCode is a closed union, grouped by origin:

CodeMeaning
invalid_credentialsWrong email / password.
account_bannedThe account is banned and cannot sign in.
email_already_existsSign-up, an account with that email already exists.
weak_passwordThe chosen password failed the environment’s strength policy.
invalid_reset_codeThe password-reset code is wrong or malformed.
provider_errorAn OAuth provider flow failed (IdP error, denied consent, callback error).
configuration_errorThe environment is misconfigured (e.g. an enabled provider with missing credentials).
signup_failedSign-up, a generic failure with no more specific code.
invitation_invalidInvitation sign-up, the invitation token is unknown, malformed, or already consumed.
invitation_expiredInvitation sign-up, the invitation has expired.
invitation_account_existsInvitation sign-up, an account already exists for the invited email (sign in instead).
captcha_failedThe Turnstile CAPTCHA challenge was rejected.
captcha_unavailableThe CAPTCHA widget couldn’t load (ad blocker, CSP).
origin_not_allowedThe browser’s origin isn’t in the environment’s allowed-origins list. Add it under Settings → Allowed origins.
expiredA one-time link / token (signup-continuation, verification) has expired.
already_usedA one-time link / token has already been consumed.
network_errorThe request never reached the server (offline, DNS, CORS, connection reset).
rate_limitedThe server returned 429. Back off and retry later.
unauthorizedThe server returned 401, not authenticated (re-authenticate).
forbiddenThe server returned 403, authenticated but not allowed.
not_foundThe server returned 404.
request_failedA non-2xx response with no more specific mapping. The default for HTTP failures.
unknownNo code could be determined (defensive fallback).

When the server sends a machine-readable code in its problem body, that code wins (so origin_not_allowed, invalid_reset_code, weak_password, … stay branchable). Otherwise the code is derived from the HTTP status: a thrown fetch → network_error; 401unauthorized; 403forbidden; 404not_found; 429rate_limited; any other non-2xx → request_failed.

The union is closed, so you can switch over it without a default and let TypeScript flag a missed case if a new code is ever added:

import type { ToriiError } from '@torii-js/torii-react';
function handleError(error: ToriiError) {
switch (error.code) {
case 'invalid_credentials':
case 'account_banned':
case 'email_already_exists':
case 'weak_password':
case 'invalid_reset_code':
case 'invitation_invalid':
case 'invitation_expired':
case 'invitation_account_exists':
return; // user-fixable, render error.message
case 'origin_not_allowed':
case 'configuration_error':
console.error('[app] Torii config error:', error.message);
return; // your setup is wrong, log it loudly in dev
case 'network_error':
case 'rate_limited':
case 'captcha_failed':
case 'captcha_unavailable':
showRetryToast();
return; // transient, offer a retry
case 'provider_error':
case 'signup_failed':
case 'unauthorized':
case 'forbidden':
case 'not_found':
case 'request_failed':
case 'expired':
case 'already_used':
case 'unknown':
reportError(error);
return;
}
}

message is a usable default, so for the common case you can render it directly and only branch on code for behaviour.

import type { ToriiError, ToriiErrorCode } from '@torii-js/torii-react';