Errors & Warnings
Overview
The Murf TTS API reports problems in two different ways depending on the transport:
- HTTP streaming (
POST /v1/speech/stream) and Synthesize (Gen 2) (POST /v1/speech/generate) return a standard HTTP status code. - WebSocket streaming (
/v1/speech/stream-input) returns JSONerrorandwarningframes on the open connection, and uses WebSocket close codes for connection-level failures.
This page covers Text to Speech. For Speech to Text, which uses different WebSocket close codes (for example 4001 for an invalid API key), see Speech to Text (Beta) errors.
How to handle errors
Every WebSocket error and warning frame carries a machine-readable code alongside the human-readable text.
- Branch on
error_codeandwarning_code, never on the prose. The wording can change at any time; the codes are stable. "fatal": truemeans nothing further is coming for that context. Stop waiting for audio orfinaland clean up.- A
warningis not fatal. Something was ignored or substituted, and audio generation continues. trace_idis present on every frame, includingaudioandfinal, not just on errors. Quote it when you contact support.
HTTP errors
These apply to POST /v1/speech/stream and POST /v1/speech/generate.
429 from HTTP streaming
A 429 from POST /v1/speech/stream includes X-Murf-Region, X-Murf-Concurrency-Limit, X-Murf-Concurrency-Used, X-Murf-Concurrency-Remaining and Retry-After (seconds), and this body:
Branch on error, not on the message text.
WebSocket errors
An error frame looks like this:
WebSocket warnings
Warnings mean something in your frame was ignored or substituted. Audio generation continues, so you will still receive audio.
Connection close codes
An invalid API key on a WebSocket connection is not reported as HTTP 401. The upgrade succeeds first, so clients that only inspect the HTTP response never see the failure. Always handle the close code.
Recommended handling pattern
Handle close code 4029 around this loop. With the websockets library, catch websockets.ConnectionClosed and check e.rcvd.code.
FAQs
Why do I get 403 instead of 401 for a bad API key?
The HTTP endpoints return 403 for both invalid and expired keys. There is no 401 response. Over WebSockets the connection is closed with code 1008 instead, because the HTTP upgrade has already completed by the time the key is rejected.
What causes ACTIVE_CONTEXT_LIMIT_EXCEEDED?
Concurrency is counted by the number of simultaneously active
context_ids, not by the number of connections. Closing each turn with
{"end": true} frees its slot. See
Rate Limits & Concurrency for per-plan numbers. The
error frame names the region and its limit, and the connection then closes
with code 4029. To see your usage before you hit the limit, read the
concurrency object on each final message; see
Check your usage.
Should I retry on a warning?
No. Warnings are informational and audio generation continues with a default or the previously accepted value. Fix the offending field in your next frame.
What should I include in a support request?
The trace_id from any frame in the affected context, the context_id,
the endpoint host you connected to, and the approximate time of the
request.