Errors

Claud uses conventional HTTP status codes and returns a consistent JSON envelope for every error, on every endpoint.

The error envelope#

JSON
{
  "error": {
    "message": "The model 'claud-ultra' does not exist or you do not have access to it.",
    "type": "invalid_request_error",
    "code": "model_not_found",
    "param": "model",
    "request_id": "req_01J9X3Q5K7M2N8P4R6T0V2W4Y6"
  }
}
messagestring
A human-readable description. Safe to log; never contains secrets.
typestring
The error family (see below). Use it for coarse handling such as "retry" versus "fix the request".
codestring
A stable machine-readable code. Branch on this, not on message.
paramstring
Present when the error relates to a specific request field, for example messages or model.
request_idstring
Identifies the request in Claud's logs. Include it when contacting support. Also returned in the x-request-id header on every response.

For 429 and some 503 errors a retry-after header tells you how many seconds to wait.

Anthropic-format endpoints#

Errors raised by POST /v1/messages follow the Messages API convention so the Anthropic SDKs surface them correctly. The code and request_id fields are the same as above:

JSON
{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "max_tokens: Invalid input: expected number, received undefined",
    "code": "invalid_request",
    "request_id": "req_01J9X3Q5K7M2N8P4R6T0V2W4Y6"
  }
}

Authentication failures on that endpoint use the standard envelope shown first; both SDK families read error.message from it.

Error types#

typeStatusMeaning
invalid_request_error400, 404, 413The request is malformed or refers to something that does not exist. Fix the request; retrying will not help.
authentication_error401The key is missing, malformed, expired or revoked.
permission_error403The key is valid but the account or plan is not allowed to do this.
insufficient_balance_error402Your token balance is too low to start the request. Top up.
not_found_error404Unknown route or resource.
conflict_error409The action conflicts with current state (for example rotating a key that is already revoked).
rate_limit_error429A per-minute, concurrency or plan cap was hit. Honour retry-after.
provider_error502, 503, 504The upstream model failed, timed out or is paused. Usually transient; retry with back-off.
maintenance_error503Claud is in scheduled maintenance.
configuration_error503A model is misconfigured on our side (for example no published price). We are alerted automatically.
server_error500Something unexpected happened. Retry once, then contact support with the request_id.

Error codes#

Request validation (400)#

codeNotes
invalid_request_errorSchema validation failed. message names the field and the problem, e.g. messages.0.content: Required.
invalid_requestA semantic problem such as too many messages; param names the field.
context_length_exceededThe prompt exceeds the context window for the model on your plan (pay-as-you-go and Starter accounts are capped at 128K tokens). Shorten the prompt or upgrade.
payload_too_largeThe request body exceeds the size limit (413).

Authentication (401)#

codeNotes
missing_api_keyNo Authorization header, or not using the Bearer scheme.
invalid_api_keyThe key is unknown, expired or revoked.

Permission (403)#

codeNotes
email_not_verifiedVerify the account's email address first.
account_inactiveThe account is suspended or scheduled for deletion.
account_blocked, api_key_blocked, ip_blockedBlocked for abuse. Contact support if you believe this is a mistake.
model_not_in_planThe model is not included in the current plan (param: "model").
api_key_limitYou have reached the maximum number of active keys for your plan.
key_management_requires_sessionCreating, rotating or revoking keys requires a dashboard session, not an API key.

Models (404)#

codeNotes
model_not_foundUnknown model slug or alias, or the model is disabled. Use GET /v1/models for the current list.

Balance (402)#

codeNotes
insufficient_balanceNot enough tokens to cover the worst-case cost of the request. Claud reserves an estimate up front and settles the actual cost afterwards, so a balance that looks "just enough" may still be rejected.

Rate limits and caps (429)#

codeNotes
rate_limit_exceededRequests per minute.
tokens_per_minute_exceededTokens per minute (prompt estimate + expected output).
concurrency_limit_exceededToo many in-flight requests.
daily_limit_exceeded, monthly_limit_exceededA plan cap was reached; resets at UTC midnight / month start.

See Rate limits for the numbers per plan and the headers to watch.

Upstream and platform (5xx)#

codeStatusNotes
provider_error502The provider returned an error. Not billed.
provider_timeout504The provider did not respond in time. Not billed.
provider_unavailable503The provider is overloaded, or the feature is temporarily disabled. retry-after: 10.
spending_limit_reached503A cost-protection budget paused the model; automatically resumes. retry-after: 60.
maintenance_mode503Scheduled maintenance. retry-after: 300.
configuration_error503Model configuration problem on our side.
internal_error500Unexpected failure.

Errors during a stream#

If a stream has already started when something fails, the HTTP status is already 200. Claud then sends an error event on the stream, followed by data: [DONE]:

Text
data: {"error":{"message":"The model provider timed out.","type":"provider_error","code":"provider_timeout","request_id":"req_..."}}

data: [DONE]

Any tokens generated before the failure are billed; the reservation for the rest is released. See Streaming.

Handling errors well#

import OpenAI, { APIError, RateLimitError } from 'openai';

const client = new OpenAI({ apiKey: process.env.CLAUD_API_KEY, baseURL: 'https://api.claudkey.com/v1', maxRetries: 3 });

try {
  const res = await client.chat.completions.create({ model: 'claud-5.1', messages });
} catch (err) {
  if (err instanceof RateLimitError) {
    // The SDK already retried with back-off; surface a friendly message.
  } else if (err instanceof APIError) {
    const code = err.error?.error?.code ?? err.code;
    if (code === 'insufficient_balance') notifyBillingOwner();
    else if (code === 'context_length_exceeded') truncateHistoryAndRetry();
    else console.error(`Claud error ${code} (request ${err.headers?.['x-request-id']})`);
  } else {
    throw err;
  }
}
  • Retry 429, 502, 503 and 504 with exponential back-off and jitter, respecting retry-after. The OpenAI SDKs do this by default.
  • Do not retry 400, 401, 402, 403 or 404; the same request will fail again.
  • Log request_id on every failure. It lets support trace the exact request across the gateway, the ledger and the provider.