Troubleshooting
Error shape matches the protocol you called. /v1/chat/completions and /v1/responses return OpenAI-style errors; /v1/messages returns Anthropic-style errors. HTTP status codes are identical across all three protocols.
Error Response Format
OpenAI format (/v1/chat/completions, /v1/responses)
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": "invalid_api_key"
}
} Anthropic format (/v1/messages)
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
} 401 · Authentication failed authentication_error
{"error":{"message":"missing API key in Authorization header or X-API-Key","type":"authentication_error"}} Causes
- No
Authorization: Bearerheader (orX-API-Key) — message:missing API key in Authorization header or X-API-Key. - The key matches no active key — message:
invalid API key. - The key is past its expiry — message:
API key expired.
Fix
- Send
Authorization: Bearer sk-syn-…(orX-API-Key: sk-syn-…). - Confirm the key is active in the console and was copied in full.
Not retryable — fix the credential.
400 · Invalid request invalid_request
{"error":{"message":"model or models field is required","type":"invalid_request"}} Causes
- The
modelfield is missing, or the JSON body is empty or malformed.
Fix
- Include a
modeland a well-formed JSON body. See the Chat Completions reference.
Not retryable — fix the request.
403 · Quota exhausted quota_exhausted
{"error":{"message":"API key quota exhausted","type":"quota_exhausted"}} Causes
- The key or workspace prepaid balance is used up.
Fix
- Top up the workspace balance. Note: Synthorai returns
403 quota_exhaustedfor a spent balance, not429— so exponential backoff will not help; only a top-up clears it.
Not retryable by backoff — top up.
403 · Compliance — no data sharing compliance_blocked / compliance_no_data_share
{"error":{"type":"compliance_blocked","code":"compliance_no_data_share","message":"model 'MODEL' is unavailable: your workspace compliance setting disallows providers that retain/train on data"}} Causes
- Your workspace has
no_provider_data_shareenabled, and the requested model is only served by a provider that requires data retention/sharing (e.g. a Bedrock or Vertex data-share-only model).
Fix
- Route the request to a zero-retention model, or turn off the workspace compliance switch if data sharing is acceptable for that workload. Retention class is a per-model routing input — see the 30-day retention breakdown.
Not retryable — a policy decision, not a transient error.
429 · Rate limited rate_limit_exceeded
{"error":{"message":"rate limit exceeded: max 60 requests per minute","type":"rate_limit_exceeded"}} Causes
- You exceeded the per-minute request ceiling (RPM). The message states the exact limit.
Fix
- Back off and retry with exponential backoff + jitter (snippet below). Request a higher limit if you need sustained throughput.
Retryable — back off and retry.
502 · No channel for the model upstream_error
{"error":{"message":"no channels available for model \"MODEL\" in group \"default\"","type":"upstream_error"}} Causes
- The model id matches no routable channel for your workspace — a typo, a delisted model, or one your plan cannot reach.
Fix
- Check the exact id against the live model list. If a model was recently retired, pick a current one.
Not retryable unchanged — correct the model id.
BYOK: upstream provider errors
With bring-your-own-key, the request runs on your provider account (AWS Bedrock, Google Vertex AI, or the Anthropic API), so Synthorai passes the provider's original error through unchanged — responses carry usage.is_byok: true. The fix lives in that provider's console or config, not in the gateway. The most common ones are account-level model-access and data-sharing settings:
| Provider error / config | Cause | Fix |
|---|---|---|
model "…" is currently unavailable | On your BYOK account the model is not enabled, was delisted, or is capacity-limited (e.g. Claude Fable 5, temporarily delisted on Bedrock). | Enable model access in the provider console (Bedrock → Model access; Vertex → Model Garden), or route to an available model. |
setPublisherModelConfig / dataSharingEnabledProvider: "anthropic" (Vertex AI) | Google Vertex AI gates Anthropic partner models behind a project-level data-sharing opt-in and Model Garden terms acceptance. | Call setPublisherModelConfig with dataSharingEnabledProvider: "anthropic" and accept the terms. See Google's Vertex partner-model docs. |
data_retention_mode: provider_data_share (AWS Bedrock) | Bedrock gates certain Claude models behind an explicit account-level data-retention opt-in; without it the model lists as unavailable. | Set data_retention_mode: provider_data_share on the account (optionally pin it with an SCP on bedrock:DataRetentionMode). |
Upstream provider errors
These pass through from the model provider with the provider's own HTTP status and type. Only 500 and 529 indicate the provider's side; treat them (and 429) as transient and retry, while 4xx reflect the request. Full reference: Anthropic's error docs.
| Status | Type | Meaning |
|---|---|---|
413 | request_too_large | The request body exceeds the size limit — reduce the payload. |
500 | api_error | The upstream provider hit an internal error — transient; retry with backoff. |
529 | overloaded_error | The upstream provider is temporarily overloaded — transient; retry with backoff. |
Rate Limits
Rate limits are enforced per API key to ensure fair usage across all users.
Default Limits
| Parameter | Type | Description |
|---|---|---|
RPM | integer | Requests per minute. Default: 60 RPM per key. |
TPM | integer | Tokens per minute. Default: 100,000 TPM per key. |
Daily Quota | integer | Total tokens per day. Configurable by admin per user. |
When a rate limit is hit, you receive a 429 response with a Retry-After header indicating the wait time in seconds.
Budgeting token throughput against real per-token prices? Run your workload through the LLM API cost calculator.
Handling 429 Errors
import time
import openai
client = openai.OpenAI(base_url="https://synthorai.io/v1", api_key="YOUR_API_KEY")
for attempt in range(5):
try:
response = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[{"role": "user", "content": "Hello"}]
)
break
except openai.RateLimitError as e:
wait = 2 ** attempt # exponential backoff
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)async function withRetry(fn, maxAttempts = 5) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
return await fn();
} catch (err) {
if (err.status === 429 && attempt < maxAttempts - 1) {
const wait = Math.pow(2, attempt) * 1000;
await new Promise(r => setTimeout(r, wait));
} else throw err;
}
}
}Hitting a 502 or overload on one model? Pick a fallback from the model price comparison — every routable model and its per-token price in one table.