> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://murf.ai/api/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://murf.ai/api/docs/_mcp/server.

# Errors

> How Murf Speech to Text reports errors, what each WebSocket close code means, and how to handle it.

## How errors are reported

The Speech to Text WebSocket reports problems in two ways:

* An **`Error` message**, sent immediately before the server closes the connection.
* A **WebSocket close code**, which identifies the cause.

```json

{ "type": "Error", "message": "Invalid audio config: missing sample_rate" }

```

**Decide what to do based on the close code, not the message text.** The text is for people and may change. The exceptions are `insufficient_credits`, `api_key_revoked`, `initial_timeout` and `idle_timeout`, which are stable values.

Every `Error` closes the connection. There are no non-fatal errors on this endpoint.

> **Note**
>
> Speech to Text and Text to Speech use different close codes. For example, an invalid API key closes a Speech to Text connection with `4001` and a Text to Speech WebSocket with `1008`. For Text to Speech errors, see [Errors & Warnings](/api/docs/text-to-speech/errors).

## Close codes

| Code   | Cause                                                                                                                                                                               | Example `message`                           | What to do                                                                                                                               | Retry?            |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| `1000` | Normal close after you sent `CloseStream`                                                                                                                                           | —                                           | Nothing.                                                                                                                                 | —                 |
| `4001` | Invalid or missing API key                                                                                                                                                          | `Unauthorized: Invalid or missing API key`  | Check the key and how you send it.                                                                                                       | No                |
| `4002` | Invalid `AudioConfig`, audio that cannot be decoded, a text frame that is not a JSON object, or an invalid query parameter                                                          | `Invalid audio config: missing sample_rate` | Fix the audio format, message or query parameter. See [Audio formats](/api/docs/speech-to-text/audio-formats).                           | No, not unchanged |
| `4003` | Insufficient credits when connecting                                                                                                                                                | —                                           | Top up in the [dashboard](https://murf.ai/api/dashboard).                                                                                | After top-up      |
| `4004` | Streaming concurrency limit for this API key reached. Each open connection uses one slot until it closes (5 on the free tier; pay as you go is 20 by default, up to 150 on request) | —                                           | Retry with exponential backoff, or see [Rate Limits & Concurrency](/api/docs/resources/rate-limits).                                     | Yes, with backoff |
| `4005` | Credits ran out during the session                                                                                                                                                  | `insufficient_credits`                      | Top up, then reconnect.                                                                                                                  | After top-up      |
| `4006` | API key revoked during the session                                                                                                                                                  | `api_key_revoked`                           | Use a valid key.                                                                                                                         | No                |
| `4008` | No audio or `KeepAlive` received after connecting (`initial_timeout`), or since the last audio or `KeepAlive` (`idle_timeout`)                                                      | `idle_timeout`                              | Send audio or `KeepAlive` more often. See [Keeping the connection open](/api/docs/speech-to-text/streaming#keeping-the-connection-open). | Yes               |
| `4010` | Billing service unreachable when connecting                                                                                                                                         | —                                           | Retry with exponential backoff.                                                                                                          | Yes, with backoff |
| `4011` | Speech detection unavailable when connecting                                                                                                                                        | `internal_error`                            | Retry with exponential backoff.                                                                                                          | Yes, with backoff |

A WebSocket request to an unknown path is rejected with HTTP `404` before the connection opens.

## Low balance warning

When your balance reaches the warning threshold, the server sends one `QuotaWarning` message per session. This is not an error: the stream keeps running until credits run out (close `4005`) or you close it.

```json
{ "type": "QuotaWarning", "remaining_funds": 0.001875 }
```

`remaining_funds` is your remaining workspace balance in USD.

## Recommended handling

```python
import json
import websockets

RETRYABLE = {4004, 4008, 4010, 4011}

async def read_results(ws):
    try:
        async for raw in ws:
            msg = json.loads(raw)
            if msg["type"] in ("partial", "final"):
                handle_transcript(msg)
            elif msg["type"] == "QuotaWarning":
                notify_low_balance(msg["remaining_funds"])
            elif msg["type"] == "Error":
                log_error(msg["message"])
    except websockets.ConnectionClosedError:
        pass

    if ws.close_code in RETRYABLE:
        schedule_reconnect_with_backoff()
    elif ws.close_code != 1000:
        alert(f"Speech to Text closed with code {ws.close_code}")
```

## Contacting support

Include the following in your support request:

* the `rawEvent.request_id` from any `partial` or `final` message on the connection
* the close code and the `message` text
* the host you connected to
* the approximate time of the session

If the connection closed before any `partial` or `final` message (for example an auth failure with code `4001`), there is no `request_id`. Include the time of the attempt, the host, how you sent the key, and the close code.