Skip to main content

Errors and retries

Things break. Good API clients make that boring: read the status, keep the request_id, and retry only when the failure is actually temporary.

Core error envelope

Authentication, model, rate-limit, and service failures use this shape:

{
"error": {
"message": "Invalid API key.",
"type": "authentication_error",
"param": null,
"code": "invalid_key"
},
"request_id": "<request-id>"
}

Use error.code for program logic, show or log error.message, and retain the request_id for support.

Some TTS validation and generation errors use a detail string or array instead:

{
"detail": "Unsupported response_format. Supported formats: wav, mp3, flac, aac, opus, pcm"
}

Clients should handle both documented JSON shapes for TTS 400, 422, and 500 responses.

Status codes

StatusMeaningClient action
400Invalid body, field, audio, or realtime eventCorrect the request; do not retry unchanged
401Missing, malformed, invalid, expired, revoked, or incorrectly scoped keyReplace or update the key
402Insufficient credit or suspended billing stateResolve billing or account state
404Wrong path or unsupported modelCheck the URL and model ID
413Request or file exceeds an endpoint limitReduce or split the input
422TTS parameter validation failedCorrect the named field
429Account or migrated-key concurrency limit reachedRespect Retry-After; retry with backoff and jitter
502Inference service failedRetry with capped exponential backoff
503Authentication, billing, or inference service unavailableRetry with capped exponential backoff
Other 5xxUnexpected server failureRetry a limited number of times

Common error codes

CodeMeaning
missing_api_keyThe bearer credential is absent
malformed_keyThe credential does not have a valid KittenML key shape
invalid_keyThe credential is unknown, revoked, or otherwise invalid
scope_not_allowedThe key lacks the permission required by the endpoint
insufficient_credit or out_of_creditsPaid ASR cannot begin with the available balance
invalid_fileThe upload is empty, oversized, or cannot be decoded
invalid_response_formatThe requested transcription representation is unsupported
rate_limit_exceededThe applicable concurrency pool is full
billing_service_unavailableAuthentication or paid-usage state cannot be checked temporarily
tts_service_unavailableSpeech generation is temporarily unavailable

Other endpoint-specific codes can be returned. Use the HTTP status for the broad error class and error.code for specific handling.

WebSocket errors

Realtime authentication and admission failures arrive as a structured error event after the WebSocket upgrade, followed by a close frame:

{
"type": "error",
"error": {
"type": "authentication_error",
"code": "invalid_key",
"message": "Invalid API key."
},
"request_id": "<request-id>"
}

The current public endpoint exposes close code 1000 for these failures. Always use error.code to classify the failure; the close code is only a transport-level signal that the session ended.

Retry safely

For retryable HTTP failures, use capped exponential backoff with random jitter. Limit the number of attempts, set a request timeout, and honor Retry-After when the response includes it. Do not retry an unchanged request for a status listed above as a client or account error.

A fresh client retry is a new inference request. If both the original and the retry succeed, both may be processed and recorded separately.