Errors
Claudech uses conventional HTTP status codes and returns a consistent JSON envelope for every error, on every endpoint.
The error envelope#
{
"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
messagesormodel. - request_idstring
- Identifies the request in Claudech's logs. Include it when contacting support. Also returned in the
x-request-idheader 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:
{
"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#
type | Status | Meaning |
|---|---|---|
invalid_request_error | 400, 404, 413 | The request is malformed or refers to something that does not exist. Fix the request; retrying will not help. |
authentication_error | 401 | The key is missing, malformed, expired or revoked. |
permission_error | 403 | The key is valid but the account or plan is not allowed to do this. |
insufficient_balance_error | 402 | Your token balance is too low to start the request. Top up. |
not_found_error | 404 | Unknown route or resource. |
conflict_error | 409 | The action conflicts with current state (for example rotating a key that is already revoked). |
rate_limit_error | 429 | A per-minute, concurrency or plan cap was hit. Honour retry-after. |
provider_error | 502, 503, 504 | The upstream model failed, timed out or is paused. Usually transient; retry with back-off. |
maintenance_error | 503 | Claudech is in scheduled maintenance. |
configuration_error | 503 | A model is misconfigured on our side (for example no published price). We are alerted automatically. |
server_error | 500 | Something unexpected happened. Retry once, then contact support with the request_id. |
Error codes#
Request validation (400)#
code | Notes |
|---|---|
invalid_request_error | Schema validation failed. message names the field and the problem, e.g. messages.0.content: Required. |
invalid_request | A semantic problem such as too many messages; param names the field. |
context_length_exceeded | The prompt exceeds the model's 1 million token context window. Shorten the prompt. |
payload_too_large | The request body exceeds the size limit (413). |
Authentication (401)#
code | Notes |
|---|---|
missing_api_key | No Authorization header, or not using the Bearer scheme. |
invalid_api_key | The key is unknown, expired or revoked. |
Permission (403)#
code | Notes |
|---|---|
email_not_verified | Verify the account's email address first. |
account_inactive | The account is suspended or scheduled for deletion. |
account_blocked, api_key_blocked, ip_blocked | Blocked for abuse. Contact support if you believe this is a mistake. |
model_not_in_plan | The model is not included in the current plan (param: "model"). |
api_key_limit | You have reached the maximum number of active keys for your plan. |
key_management_requires_session | Creating, rotating or revoking keys requires a dashboard session, not an API key. |
Models (404)#
code | Notes |
|---|---|
model_not_found | Unknown model slug or alias, or the model is disabled. Use GET /v1/models for the current list. |
Balance (402)#
code | Notes |
|---|---|
insufficient_balance | Not enough tokens to cover the worst-case cost of the request. Claudech 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)#
code | Notes |
|---|---|
rate_limit_exceeded | Requests per minute. |
tokens_per_minute_exceeded | Tokens per minute (prompt estimate + expected output). |
concurrency_limit_exceeded | Too many in-flight requests. |
daily_limit_exceeded, monthly_limit_exceeded | A 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)#
code | Status | Notes |
|---|---|---|
provider_error | 502 | The provider returned an error. Not billed. |
provider_timeout | 504 | The provider did not respond in time. Not billed. |
provider_unavailable | 503 | The provider is overloaded, or the feature is temporarily disabled. retry-after: 10. |
spending_limit_reached | 503 | A cost-protection budget paused the model; automatically resumes. retry-after: 60. |
maintenance_mode | 503 | Scheduled maintenance. retry-after: 300. |
configuration_error | 503 | Model configuration problem on our side. |
internal_error | 500 | Unexpected failure. |
Common error messages#
"Provider returned error"#
Many AI API services show this text when the model behind them fails. On Claudech the same situation returns 502 with the code provider_error and the message "The upstream model provider returned an error." These requests are not billed. Retry with back-off; if one model keeps failing, try another model and send support the request_id.
"Invalid beta flag"#
Anthropic-format clients such as Claude Code and the Anthropic SDKs can send an anthropic-beta header that turns on experimental features. Endpoints that do not recognise a flag reject the request with "invalid beta flag". Claudech's POST /v1/messages accepts the header and ignores it, so this error does not come from Claudech. If you see it, the client is still sending requests somewhere else: in Claude Code, check that ANTHROPIC_BASE_URL is exactly https://api.claudech.com (Claude Code setup).
"Rate limit reached"#
A 429 with rate_limit_exceeded, tokens_per_minute_exceeded or concurrency_limit_exceeded. Wait for the number of seconds in retry-after and send the request again. The limits for each plan are on Rate limits.
"Insufficient balance"#
A 402 with insufficient_balance: the balance cannot cover the worst-case cost of the request. Top up under Billing; retrying without topping up fails the same way.
Errors during a stream#
If a stream has already started when something fails, the HTTP status is already 200. Claudech then sends an error event on the stream, followed by data: [DONE]:
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.CLAUDECH_API_KEY, baseURL: 'https://api.claudech.com/v1', maxRetries: 3 });
try {
const res = await client.chat.completions.create({ model: 'claude-opus-5-5', 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(`Claudech error ${code} (request ${err.headers?.['x-request-id']})`);
} else {
throw err;
}
}- Retry
429,502,503and504with exponential back-off and jitter, respectingretry-after. The OpenAI SDKs do this by default. - Do not retry
400,401,402,403or404; the same request will fail again. - Log
request_idon every failure. It lets support trace the exact request across the gateway, the ledger and the provider.