Skip to content
Guides/Using the API

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

StatusMeaningWhat to Do
400Invalid requestCheck the model, parameters, and request format.
401Authentication failedCheck your key and API URL.
402Credits or a spend limitAdd credits, or check which budget metadata names and when it resets.
403Access deniedCheck key scopes (text needs llm.write), workspace permissions, and the access policy metadata names.
404Not foundVerify the resource ID and endpoint path.
408Language request timed outInspect the request before submitting it again.
409ConflictInspect the existing request or resource revision.
413 / 415Unsupported inputReduce the payload or use a supported media type.
422Unsupported configurationCheck the model’s capabilities and parameter limits.
429Rate or concurrency limitRespect Retry-After when present; reduce concurrency.
500 / 502Service or provider failureInspect request logs and provider status.
503No eligible endpointCheck 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:

errors.mjs
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
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

  1. Confirm the API URL, workspace, and model ID.
  2. Save the returned request ID, HTTP status, and error code.
  3. Open Logs in the same workspace to inspect available request details.
  4. 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.