Errors and Debugging
Understand failures, handle retries, and trace a request.
Diagnose a Failed Request
Start with the HTTP status and error message, then check the URL, key, and model. A 401 or 403 is usually an authentication or permission issue; a 402 concerns available credits or spending limits. A 503 can mean a disabled integration or no eligible route, so retrying alone may not resolve it.
If a file appears corrupt, check whether you saved an error response as audio. If an SDK reports an unknown path, check for a missing or duplicated /v1. If a file upload fails validation, let the client set its multipart boundary.
Error Responses
Check the HTTP status before reading a response. Every endpoint returns a string error code. Media and workspace endpoints add a request identifier. Language endpoints add an error type that OpenAI and Anthropic clients understand, and metadata with the provider, its upstream status, the limit reached, or each failed attempt. Messages wraps the same object as {"type": "error", "error": {...}}.
A language request without streaming that runs longer than 30 seconds is answered with status 200 and leading spaces while it runs, so the connection stays open. If it then fails, the error object arrives in that 200 body, so check for error before reading the result.
{
"error": {
"code": "bad_request",
"message": "Invalid request body",
"param": "model",
"request_id": "req_example"
}
}HTTP Status Codes
| Status | Meaning | What to Do |
|---|---|---|
400 | Invalid request | Check the model, parameters, and request format. |
401 | Authentication failed | Check your key and API URL. |
402 | Credits or a spend limit | Add credits, or check which budget metadata names and when it resets. |
403 | Access denied | Check key scopes (text needs llm.write), workspace permissions, and the access policy metadata names. |
404 | Not found | Verify the resource ID and endpoint path. |
408 | Language request timed out | Inspect the request before submitting it again. |
409 | Conflict | Inspect the existing request or resource revision. |
413 / 415 | Unsupported input | Reduce the payload or use a supported media type. |
422 | Unsupported configuration | Check the model’s capabilities and parameter limits. |
429 | Rate or concurrency limit | Respect Retry-After when present; reduce concurrency. |
500 / 502 | Service or provider failure | Inspect request logs and provider status. |
503 | No eligible endpoint | Check model availability, routing constraints, and gateway access. |
Read an Error
Capture the status, error code, and request ID. Avoid logging credentials or request content.
This helper accepts a failed HTTP response. It also handles non-JSON errors, such as a response from a proxy:
export async function readError(response) {
const raw = await response.text();
let body;
try {
body = JSON.parse(raw);
} catch {
body = {};
}
return {
status: response.status,
code: body.error?.code ?? "unknown",
message: body.error?.message ?? response.statusText,
requestId: body.error?.request_id ?? response.headers.get("x-request-id"),
};
}Call readError(response) when response.ok is false. Reading the body consumes it, so keep the returned details for later handling. Review error messages before sending them to logs that are accessible outside your team.
Retries and Rate Limits
For rate limits, respect Retry-After when it is present. Otherwise use exponential backoff with jitter and a small retry budget. Correct authentication, validation, and credit errors before retrying.
A timeout does not prove that inference failed: the provider may already have processed the request. Keep the same idempotency key when retrying the same logical operation on an endpoint that supports it. Language endpoints can return 409 for an existing request; this is not permission to create a new billable request.
HTTP/1.1 429 Too Many Requests
Retry-After: 5
Content-Type: application/json
{"error":{"code":"rate_limited","type":"rate_limit_error","message":"Rate limit exceeded","param":null,"metadata":{"limit":"key_rate_limit","retry_after_seconds":5}}}Streaming Failures
Before a stream opens, errors use an HTTP error response. A language stream holds its status line until output starts, so when every candidate fails first you get an HTTP error, not an error event. After output starts, a failure arrives as a protocol error event or a closed connection; the HTTP status cannot change.
Handle errors throughout the stream, retain partial output separately, and wait for the protocol’s completion signal. A disconnected stream is not a completed response. Do not replay tool actions automatically when reconnecting.
Trace a Request
- Confirm the API URL, workspace, and model ID.
- Save the returned request ID, HTTP status, and error code.
- Open Logs in the same workspace to inspect available request details.
- Check Usage for settled usage before resubmitting an ambiguous request. An absent charge does not prove that a disconnected request did no work.
For provider failures, inspect metadata when it is returned. A language response’s x-audiolab-routing header lists every provider attempt and why it failed; see Read the Routing Explanation. Share a request ID when reporting a problem; never share your API key.