Errors
Error codes, formats, and handling for the Sansa API
Error Formats
OpenAI-compatible endpoints such as Chat Completions, Responses, and Transcriptions use Sansa's OpenAI-shaped error object. If your code already handles OpenAI errors, it can handle these endpoints unchanged.
{
"error": {
"code": "invalid_request",
"message": "Human-readable description of what went wrong.",
"request_id": "a3f2c1d0-8b4e-4f9a-b2d1-7c5e3a1f0e9b"
}
}The Anthropic-compatible Messages endpoints use Anthropic's error envelope instead:
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "What went wrong and how to fix it."
},
"request_id": "req_..."
}This applies to /v1/messages, /v1/messages/count_tokens, /v1/mcp_servers, and Claude Code model-discovery errors. See Messages errors for its status mapping, request IDs, upstream-error preservation, and terminal SSE error events.
OpenAI-compatible error fields
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error identifier. See the reference below. |
message | string | What went wrong and how to fix it. |
request_id | string | Present on errors that occur after the request is accepted. Use this when contacting support. Not present on auth errors. |
HTTP Status Codes
| Status | Meaning |
|---|---|
400 | Bad request — invalid body, unsupported parameter, or value out of range |
401 | Unauthorized — missing or invalid API key |
402 | Payment required — insufficient credits or spend cap exceeded |
403 | Forbidden — key scope, model policy, or abuse policy rejected the request |
404 | Not found — route or optional capability is unavailable |
413 | Request too large |
429 | Rate limited — too many requests |
500 / 502 | Internal or upstream provider error |
503 | Upstream provider unavailable |
504 | Upstream timeout |
529 | Upstream provider overloaded |
Error Code Reference
invalid_request
HTTP 400. The request body is structurally invalid or a value is out of range.
Common causes:
messagesis missing or empty- A field type is wrong (e.g.,
content: 123instead of a string) temperatureis not between 0 and 2top_pis not between 0 and 1frequency_penaltyorpresence_penaltyis not between -2 and 2max_tokensormax_completion_tokensis less than 1stopcontains more than 4 sequencesmetadatahas more than 16 key-value pairs, a key over 64 characters, or a value over 512 charactersresponse_format.typeis"json_schema"but nojson_schemaobject was provided- A
toolmessage is missingtool_call_id - Malformed JSON body
- On
/v1/audio/transcriptions,sansaormetadataform fields that are not valid JSON objects
invalid_model
HTTP 400. The model value isn't "sansa-auto", null, or a known model ID from the catalog.
Pass "sansa-auto" to use intelligent routing, or a specific model ID (e.g. "openai/gpt-5.4") to call it directly. The full list of supported IDs lives on the Models page in your dashboard. See Models for details.
invalid_call_name
HTTP 400. A call_name value is invalid: empty, whitespace-only, or exceeds 64 characters. Applies to sansa.call_name, metadata.call_name, and the top-level call_name field on transcriptions.
invalid_end_user_id
HTTP 400. An end_user_id value is invalid: empty, whitespace-only, or exceeds 512 characters. Applies to sansa.end_user_id and metadata.end_user_id on chat completions and transcriptions.
unsupported_parameter
HTTP 400. A parameter was provided that Sansa does not support.
| Parameter | Why rejected |
|---|---|
audio | Audio output is not supported |
modalities (with "audio") | Only text modality is supported |
web_search_options | Web search is not supported |
n > 1 | Only one completion per request |
functions | Deprecated — use tools |
function_call | Deprecated — use tool_choice |
unauthorized
HTTP 401. The API key is missing, malformed, or invalid.
- No
Authorizationheader - Missing
Bearerprefix — must beAuthorization: Bearer <api-key> - API key is revoked or does not exist
request_id is not present on auth errors.
insufficient_credits
HTTP 402. Your account balance is zero or insufficient for the request.
Add credits from your dashboard.
SDK note: HTTP 402 is not part of OpenAI's standard error set. The OpenAI SDK surfaces it as a generic APIStatusError. Catch it by checking error.status === 402 or the code field.
spend_cap_exceeded
HTTP 402. The request would exceed a configured spend cap in block mode.
The message names the scope and rolling window, for example:
This request would exceed the 30-day spend cap for this organization.
Other examples: daily spend cap for this environment, 30-day spend cap for this API key. See Spend caps for scope types, how caps stack, and where to configure them.
This is not the same as running out of credits. Check error.code: spend_cap_exceeded vs insufficient_credits.
Do not retry until the rolling window spend drops or you raise the cap in your dashboard.
rate_limit_exceeded
HTTP 429. Your API key has exceeded its rate limit, or the upstream provider returned a rate limit error. Retry with exponential backoff.
upstream_invalid_request
HTTP 400. The request passed Sansa's local validation but was rejected by the upstream model. Do not retry unchanged. If the guidance does not identify a fix, contact support with the request_id.
provider_unavailable
HTTP 503. The upstream model is temporarily unavailable. Retry with backoff.
provider_error
HTTP 502. The upstream model returned a server-side or malformed response. Retry with backoff.
invalid_file_format
HTTP 400. The uploaded audio file has an unsupported format. Supported formats for /v1/audio/transcriptions: mp3, wav, m4a, webm, ogg, flac, opus.
file_too_large
HTTP 400. The uploaded audio file exceeds the maximum allowed size (25 MB).
unsupported_response_format
HTTP 400. The response_format value is not supported by the transcriptions endpoint.
internal_error
HTTP 500. An unexpected error in the Sansa API. Contact support with the request_id.
Errors in Streaming Responses
Pre-stream errors
If validation, auth, or credits fail before streaming begins, the response is a normal JSON error body with the appropriate endpoint-specific envelope and HTTP status code — not an SSE stream.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error":{"code":"invalid_request","message":"..."}}Chat Completions mid-stream errors
If an error occurs after a Chat Completions stream has started (HTTP 200 already sent), it is delivered in a data: event. The stream ends with [DONE].
data: {"choices":[{"finish_reason":"error"}],"error":{"code":"provider_error","message":"The upstream model returned an error. Please retry."}}
data: [DONE]Detect mid-stream errors by checking finish_reason === "error".
Responses mid-stream errors
Responses uses named SSE. A failure after streaming begins arrives as a terminal response.failed event rather than an OpenAI error chunk. See Responses streaming.
Messages mid-stream errors
Messages also uses named SSE, but its terminal failure is an Anthropic event: error:
event: error
data: {"type":"error","error":{"type":"overloaded_error","message":"..."},"request_id":"req_..."}There is no [DONE] and no message_stop after a Messages error. See Messages streaming.
Handling OpenAI-compatible Errors
Python
import openai
client = openai.OpenAI(
api_key="sk-sansa-...",
base_url="https://api.sansaml.com/v1",
)
try:
response = client.chat.completions.create(
model="sansa-auto",
messages=[{"role": "user", "content": "Hello"}],
)
except openai.AuthenticationError as e:
# 401
print(e.body["error"]["message"])
except openai.BadRequestError as e:
# 400
print(e.body["error"]["code"], e.body["error"]["message"])
except openai.RateLimitError as e:
# 429
print("Retry after a short delay")
except openai.APIStatusError as e:
# 402, 500, etc.
request_id = e.body.get("error", {}).get("request_id")
print(f"Error {e.status_code}. Request ID: {request_id}")TypeScript
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "sk-sansa-...",
baseURL: "https://api.sansaml.com/v1",
});
try {
const response = await client.chat.completions.create({
model: "sansa-auto",
messages: [{ role: "user", content: "Hello" }],
});
} catch (err) {
if (err instanceof OpenAI.AuthenticationError) {
console.error(err.error.message);
} else if (err instanceof OpenAI.BadRequestError) {
console.error(err.error.code, err.error.message);
} else if (err instanceof OpenAI.RateLimitError) {
console.error("Rate limited — retry with backoff");
} else if (err instanceof OpenAI.APIError) {
const requestId = (err.error as any)?.request_id;
console.error(`Error ${err.status}. Request ID: ${requestId}`);
}
}Detecting Chat Completions mid-stream errors
for chunk in stream:
if chunk.choices and chunk.choices[0].finish_reason == "error":
break
# process chunk normallyRetry Strategy
| Error code | Retryable? | Action |
|---|---|---|
invalid_request | No | Fix the request |
invalid_model | No | Use sansa-auto or a valid model ID |
invalid_call_name | No | Fix the call_name value |
invalid_end_user_id | No | Fix the end_user_id value |
unsupported_parameter | No | Remove the unsupported field |
invalid_file_format | No | Use a supported audio format |
file_too_large | No | Reduce file size below 25 MB |
unsupported_response_format | No | Use a supported response format |
unauthorized | No | Check your API key |
insufficient_credits | No | Add credits, then retry |
spend_cap_exceeded | No | Raise the cap or wait for the rolling window to pass |
rate_limit_exceeded | Yes | Exponential backoff |
upstream_invalid_request | No | Contact support |
provider_unavailable | Yes | Exponential backoff |
provider_error | Yes | Exponential backoff |
internal_error | Rarely | Retry once; contact support if it persists |