Skip to main content

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.

StatusMeaningHow to resolve
400Bad request — invalid or missing parametersCheck the request body and required fields; see the error message for the specific field.
401Authentication failedVerify the full API key and bearer header. See Authentication.
403Access deniedThe key is valid but is not allowed to use the requested service, provider, or model.
404Service/provider not found, or private model hiddenRecheck the route/model and the key's access.
429Rate limit exceededSlow down and retry with backoff. See Rate limits.
500Router or backend internal failureRetry after a short delay; if it persists, contact support via the platform.
502Selected backend could not be reachedRetry with backoff; the failure occurred between the router and backend.
503Service, dependency, or WebSocket admission temporarily unavailableRetry 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.

tip

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:

Next steps