SDK
Errors
OpenAI-compat type and code names as the gateway ships them. Official SDKs already know these names.
Catch the official client’s error class, then branch on status and code.
import OpenAI, { APIError } from "openai";
try {
await client.chat.completions.create({ /* … */ });
} catch (err) {
if (err instanceof APIError) {
console.error(err.status, err.code, err.error);
}
throw err;
}from openai import APIError, AuthenticationError, NotFoundError, RateLimitError
try:
client.chat.completions.create(...)
except AuthenticationError as e:
print("401", e.code)
except NotFoundError as e:
print("404", e.code, e.body)
except RateLimitError as e:
print("429", e.code)
except APIError as e:
print(e.status_code, e.code, e.body)OpenAI-compat
/v1/chat/completions, /v1/completions, and /v1/responses. A stream’s in-band error object matches the buffered envelope.
| Status | type | code | Meaning |
|---|---|---|---|
| 401 | invalid_request_error | invalid_api_key | Message Incorrect API key provided. Header WWW-Authenticate: Bearer. All auth failures are this one 401. |
| 402 | insufficient_allowance | insufficient_quota | Billing is not set up, or the balance cannot cover the request's worst case. Stays 402; not remapped to 429. |
| 402 | cost_ceiling_exceeded | stays type | The per-request ceiling x-conifer-max-cost-nanousd refused the worst case. Stays 402. |
| 429 | rate_limit_error | rate_limit_exceeded | Header Retry-After: 1. No invented x-ratelimit-* remaining-quota figures. |
| 404 | see body | model_not_found | param model. The body does not echo the id. Close matches may list error.suggestions. |
| 400 | invalid_request_error | context_length_exceeded | The prompt is over the model's context window. Other 400s still name the problem in the body, including tools or a modality the model does not declare. Capability refusals stay 400; they are not remapped to 402 or 429. |
Anthropic /v1/messages
Types were already industry-shaped and stay that way. Official Anthropic clients keep reading the same type names.
Request ids
request-id and x-request-id echo the same value as x-conifer-request-id.
What we do not do
All auth failures are one 401. 402 is billing or the spend ceiling, never a missing tool or modality. 429 is rate limit only. Capability mismatches stay 400 and name the problem. Upstream identity is not leaked: no OpenRouter provider metadata. Remaining quota is not invented on x-ratelimit-* headers.
Bodies
{
"error": {
"message": "Incorrect API key provided",
"type": "invalid_request_error",
"code": "invalid_api_key"
}
}{
"error": {
"type": "insufficient_allowance",
"code": "insufficient_quota",
"docs_url": "https://conifer.build/console#/billing"
}
}{
"error": {
"type": "cost_ceiling_exceeded"
}
}{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
}
}{
"error": {
"code": "model_not_found",
"param": "model"
}
}{
"error": {
"type": "invalid_request_error",
"code": "context_length_exceeded"
}
}