Errors
The complete, closed set of error codes Selyf's API can return, what each one means, and what to do about it.
Response shape
Every error response from every route in the API Reference has this exact shape: { error: { code, message, requestId, details? } }. code is always one of the values below, message is a fixed, generic public message (never internal detail: no stack traces, no query fragments, no upstream provider text), requestId can be included when reporting a persistent error, and details only appears for VALIDATION_FAILED and only ever names which fields failed, never their values.
AUTH_REQUIRED
HTTP 401Caller is not authenticated.
- When it occurs
- A request to an endpoint that requires a session was made with no valid session cookie.
- What to do
- Send the user through GET /auth/google to sign in, then retry.
FORBIDDEN
HTTP 403Authenticated, but not allowed to touch this resource.
- When it occurs
- For example, a missing or invalid status-admin token on POST/PATCH /api/status/incidents.
- What to do
- Verify the caller has the correct credential for that specific route -- this is not a session problem, retrying with the same credential will not help.
CSRF_FAILED
HTTP 403A state-changing request was missing or failed CSRF validation.
- When it occurs
- The X-CSRF-Token header is missing or does not match the session, or the Origin header is not the configured web origin -- on disconnect, account deletion, sync, analyze, or draft.
- What to do
- Fetch a fresh token from GET /auth/session and retry with it in the X-CSRF-Token header.
OAUTH_FAILED
HTTP 400The OAuth authorization flow failed or was tampered with.
- When it occurs
- Google's token exchange or userinfo request failed, or the callback's state parameter did not match the one issued.
- What to do
- Restart sign-in from GET /auth/google -- this is not retryable with the same authorization code.
TOKEN_EXPIRED
HTTP 401Stored OAuth credentials are expired or were revoked upstream.
- When it occurs
- Google has invalidated the stored refresh token outside of this application (e.g. the user revoked access from their Google Account settings).
- What to do
- Prompt the user to reconnect their Google account.
VALIDATION_FAILED
HTTP 400Request payload, query, or path parameters failed schema validation.
- When it occurs
- For example, limit/offset out of range on GET /api/mail/threads, a malformed thread id, or an account-deletion body that is not exactly { "confirm": true }.
- What to do
- Read the response’s details.issues field for which fields failed, fix them, and resubmit.
NOT_FOUND
HTTP 404The resource does not exist, or the caller may not know that it exists.
- When it occurs
- A thread id that does not belong to the authenticated account, or a route that does not exist.
- What to do
- Verify the id or path. Retrying the same request will not succeed.
RATE_LIMITED
HTTP 429Caller exceeded this application's own rate limits.
- When it occurs
- The global or a per-route rate limit was tripped, or a sync was already in progress for the account.
- What to do
- Wait the number of seconds in the Retry-After response header before retrying.
GMAIL_RATE_LIMITED
HTTP 429The Gmail API itself refused the request due to quota or rate limits.
- When it occurs
- A sync call hit Gmail’s own rate limit, not this application’s.
- What to do
- Wait and retry the sync later.
AI_RATE_LIMITED
HTTP 429The configured AI provider refused the request due to quota or rate limits.
- When it occurs
- The AI provider itself (Anthropic or Gemini) rate-limited an analyze or draft call.
- What to do
- Wait and retry later.
AI_BUDGET_EXCEEDED
HTTP 429The account's configured AI token budget is exhausted.
- When it occurs
- This account's daily or monthly AI_DAILY_TOKEN_BUDGET/AI_MONTHLY_TOKEN_BUDGET has been reached.
- What to do
- Wait for the daily or monthly budget window to reset -- an immediate retry will not succeed.
AI_REQUEST_FAILED
HTTP 502The AI provider request failed for a reason other than rate limiting.
- When it occurs
- The configured AI provider returned an error or an unreadable response.
- What to do
- Retry later. If it persists, treat it as a temporary AI-provider outage.
SYNC_FAILED
HTTP 502Mailbox synchronization failed.
- When it occurs
- The Gmail API request during POST /api/mail/sync failed for a reason other than Gmail's own rate limiting.
- What to do
- Retry the sync later.
INTERNAL_ERROR
HTTP 500Catch-all for an unexpected server error. Never carries internal detail to the client.
- When it occurs
- Anything not already one of the codes above.
- What to do
- Retry later. If it persists, note the response’s requestId when reporting it.