Errors
When a request fails, Shisa services signal the problem with an HTTP status code and a JSON body describing what went wrong. This guide covers the status codes you will see, the JSON shapes that carry the detail, and where to find per-endpoint error tables.
HTTP status codes
Check the response status first — it tells you the category of the problem and how to resolve it.
| Status | Meaning | How to resolve |
|---|---|---|
400 | Bad request — invalid or missing parameters | Check the request body and required fields; see the error message for the specific field. |
401 | Authentication failed | Verify the full API key and bearer header. See Authentication. |
403 | Access denied | The key is valid but is not allowed to use the requested service, provider, or model. |
404 | Service/provider not found, or private model hidden | Recheck the route/model and the key's access. |
429 | Rate limit exceeded | Slow down and retry with backoff. See Rate limits. |
500 | Router or backend internal failure | Retry after a short delay; if it persists, contact support via the platform. |
502 | Selected backend could not be reached | Retry with backoff; the failure occurred between the router and backend. |
503 | Service, dependency, or WebSocket admission temporarily unavailable | Retry with backoff, unless the endpoint-specific error says configuration or access must change. |
JSON error shapes
Error bodies vary between router-generated and backend-forwarded responses. Always read the HTTP status first. If the body is JSON, error may be either a string or an object containing fields such as code and message.
Router errors
Most router-generated HTTP errors use a numeric code, named error, context, and string message:
{
"context": ["authMiddleware"],
"code": 104,
"name": "ErrAuthenticationFailed",
"error": "Authentication error: Invalid token"
}
Structured and backend errors
Some validation and WebSocket-admission errors use an object-valued error:
{
"error": {
"code": "tts_text_too_long",
"message": "TTS text exceeds maximum length",
"max_chars": 5000,
"actual_chars": 5001
}
}
Backends can return other JSON shapes or even a non-JSON body, and the router may forward that status and body unchanged. Do not branch on exact message text.
Always check response.ok (or the status code) before parsing the body. A 429 or 500 may not contain the JSON your success path expects, so branching on status first avoids a second, confusing parse error.
Checking status before parsing, in practice:
const response = await fetch(url, options);
if (!response.ok) {
const detail = await response.json().catch(() => null);
const error = detail?.error;
const message =
typeof error === 'string'
? error
: error?.message ?? detail?.message ?? response.statusText;
throw new Error(`Shisa request failed (${response.status}): ${message}`);
}
const data = await response.json();
response = requests.post(url, headers=headers, json=payload)
if not response.ok:
try:
detail = response.json()
except ValueError:
detail = {}
error = detail.get("error")
message = error if isinstance(error, str) else (
error.get("message") if isinstance(error, dict) else None
)
raise RuntimeError(
f"Shisa request failed ({response.status_code}): "
f"{message or detail.get('message') or response.reason}"
)
data = response.json()
Per-service error details
Error fields and exact messages vary by endpoint. For endpoint-specific error tables and request requirements, see each service's API reference:
- ASR — endpoints reference
- TTS — endpoints reference
- Translation — endpoints reference
- LLM — responses follow the OpenAI-compatible schema; see the LLM section.
Next steps
- Rate limits — handling
429with retries and backoff. - Authentication — fixing
401errors.