> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corti.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors

> Error messages and solutions from Corti's API

Corti uses standard HTTP status codes. `4xx` errors indicate a problem with the request; `5xx` errors indicate a problem on Corti's side. Error responses are in JSON and differ between the SDKs and the REST API. The tabs below cover each.

<Note>
  Some Corti products handle errors and authentication differently than what is described below:

  * **Admin API** — Separate from the `Corti API` used for speech to text, text generation, and agentic workflows. See the [Administration API](/about/admin-api) reference for details. Please [contact us](https://help.corti.app) if you have interest in this functionality or further questions.
  * **Agents API** — The JSON format of the error response  is different. See the [Agents API](/agentic/overview) docs for more info.
  * **Embedded Assistant** — Authentication is handled differently. See the [Embedded Assistant Authentication](https://docs.corti.ai/assistant/authentication) docs for those methods.
</Note>

<div className="errors-tabs">
  <Tabs>
    <Tab title="JavaScript SDK">
      The SDK throws typed error classes on any non-2xx response or internal failure. Each class exposes a different set of attributes. See [Error Handling](/sdk/js/overview#error-handling) for full details.

      ## Error Classes

      | Class           | Thrown when                                                       | Attributes                                     |
      | --------------- | ----------------------------------------------------------------- | ---------------------------------------------- |
      | `CortiError`    | API returned a non-2xx HTTP response (4xx / 5xx)                  | `message`, `statusCode`, `body`, `rawResponse` |
      | `CortiSDKError` | SDK infrastructure error (e.g. localStorage unavailable)          | `message`, `code`, `cause`                     |
      | `ParseError`    | Input validation failed (e.g. missing PKCE verifier, invalid JWT) | `message`, `errors`                            |
      | `JsonError`     | Response body could not be parsed as JSON                         | `message`, `errors`                            |

      ## HTTP Status Codes

      <AccordionGroup>
        <Accordion title="400 — Bad Request">
          | Error code    | When it occurs                                                                 | How to resolve                                                                       |
          | ------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
          | `bad_request` | The request body or query parameters are malformed or missing required fields. | Double check the fields submitted to be sure of correct format and necessary fields. |
        </Accordion>

        <Accordion title="401 — Unauthorized">
          Token endpoint errors are returned as JSON in the response body. Corti API errors are returned in the `WWW-Authenticate` response header with no body. The header is not accessible from the exception directly; use `.WithRawResponse()` on the request if you need it.

          | Error code            | When it occurs                                                                                           | How to resolve                                                 |
          | --------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
          | `invalid_client`      | Client authentication failed. There is a problem with the client ID.                                     | Verify your `client_id` is correct.                            |
          | `unauthorized_client` | Client authentication failed. There is a problem with the client secret.                                 | Verify your `client_secret` is correct.                        |
          | `invalid_token`       | The bearer token is invalid or has expired. Check the `WWW-Authenticate` header for `error_description`. | Re-authenticate to obtain a fresh token and retry the request. |
        </Accordion>

        <Accordion title="403 — Forbidden">
          | When it occurs                                                                                          | How to resolve                                                  |
          | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
          | Accessing a resource (interaction, recording, transcript, document) that belongs to a different client. | Verify the resource ID was created by the authenticated client. |
        </Accordion>

        <Accordion title="404 — Not Found">
          | Error                                       | When it occurs                         | How to resolve                                                                                  |
          | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
          | `Invalid '{resource_name}' '{resource_id}'` | The requested resource does not exist. | Verify the ID and parent resource ID is correct and was created under the authenticated tenant. |

          <Note>
            Attempting to access a resource that belongs to a different OAuth client also returns a 404, not a 403. This is intentional. Returning a 403 would confirm that the resource exists, which is a security risk.
          </Note>
        </Accordion>

        <Accordion title="429 — Too Many Requests">
          You have exceeded the rate limit for the API. The SDK automatically retries with exponential backoff. The default retry limit is 2. Override per request:

          ```js theme={null}
          const response = await client.interactions.create(..., {
              maxRetries: 0, // disable retries for this request
          });
          ```

          If the error persists, reduce request frequency or contact [support](https://help.corti.app/) to discuss your rate limit requirements.
        </Accordion>

        <Accordion title="500 — Internal Server Error">
          An unexpected error occurred on the Corti side. Double check the request format and retry the request. If the issue persists, contact [support](https://help.corti.app/).
        </Accordion>

        <Accordion title="503 — Service Unavailable">
          The service is temporarily unavailable. Retry with exponential backoff. Monitor the [status page](https://status.corti.ai).
        </Accordion>
      </AccordionGroup>

      ## WebSocket APIs

      WebSocket errors from `/streams` and `/transcribe` are surfaced as plain `Error` objects whose `message` is the server status code (e.g. `CONFIG_DENIED`, `CONFIG_MISSING`, `CONFIG_TIMEOUT`).

      <Tip>
        Every `CONFIG_*` server message also carries a `reason` field with human-readable details behind the failure. Whether you can read it depends on the mode you connected in:

        * **Default mode** (`client.stream.connect({ id, configuration })` / `client.transcribe.connect({ configuration })`): the SDK handles the handshake-phase and `CONFIG_*` messages internally. It rejects `connect()` with just the bare code. The `reason` is not exposed.
        * **`awaitConfiguration: false`** or **[manual mode](/sdk/js/websockets#connecting-without-configuration)**: the raw message, including `msg.reason`, flows through `socket.on('message', …)`.
      </Tip>

      <Accordion title="`CONFIG_DENIED`">
        > You sent a config message, but it's invalid.

        | `reason` from server                                                                | Likely cause                                                  | Fix                                                                             |
        | ----------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------- |
        | `invalid language code: must be a valid BCP 47 language tag`                        | `transcription.primaryLanguage` is not a supported code.      | Use a [supported language code](https://docs.corti.ai/stt/languages).           |
        | `invalid output locale: language should not be empty`                               | `mode.type: "facts"` without `mode.outputLocale`.             | Add `outputLocale`.                                                             |
        | `invalid output locale: invalid language code: must be a valid BCP 47 language tag` | `mode.type: "facts"` with invalid `mode.outputLocale` code.   | Use a [supported language code](https://docs.corti.ai/stt/languages)            |
        | `unknown mode`                                                                      | `mode.type` is not `"transcription"` or `"facts"`.            | Use one of the two supported values.                                            |
        | `invalid participants`                                                              | Participant `role` outside `doctor` / `patient` / `multiple`. | Use one of the three supported roles.                                           |
        | `invalid audio format: MIME type not allowed...`                                    | `audioFormat` MIME type is not in the supported list.         | Use a [supported MIME type](https://docs.corti.ai/stt/audio) or omit the field. |
      </Accordion>

      <Accordion title="`CONFIG_MISSING`">
        > You sent a non-config frame before any valid `config` message arrived.

        Only reachable when you opt out of the [automatic handshake](/sdk/js/websockets#connecting). Default mode sends config for you.

        | `reason` from server                              | Cause                                                                                                                                                                                                  | Fix                                                                                                                                             |
        | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
        | `No valid configuration provided for interaction` | A non-config frame reached the server before a config message. Typically sendAudio() / sendFlush() / sendEnd() in manual mode, or a raw socket.send() queued before OPEN in awaitConfiguration: false. | Be sure to call sendConfiguration() immediately after waitForOpen(), or pass configuration to connect() and let the SDK handle the handshake.\` |
      </Accordion>

      <Accordion title="`CONFIG_TIMEOUT`">
        > The 10-second handshake window elapsed without any `config` message arriving.

        Only reachable in [manual mode](/sdk/js/websockets#connecting-without-configuration). The [default handshake](/sdk/js/websockets#connecting) sends config well within the 10s budget.

        | `reason` from server                              | Cause                                 | Fix                                                           |
        | ------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------- |
        | Manual mode: no configuration provided within 10s | Server's 10s handshake timer expired. | Call `sendConfiguration()` immediately after `waitForOpen()`. |
      </Accordion>
    </Tab>

    <Tab title="C# .NET SDK">
      The SDK throws typed exceptions on any non-2xx response. Each exception extends `CortiClientApiException`, which exposes `Message`, `StatusCode`, and `Body`. See [Error Handling](/sdk/dotnet/overview#error-handling) for full details.

      ## Exceptions

      | Exception class           | Thrown when               | Attributes                      |
      | ------------------------- | ------------------------- | ------------------------------- |
      | `CortiClientApiException` | Any non-2xx HTTP response | `Message`, `StatusCode`, `Body` |

      Each status code throws a typed subclass with a more specific `Body`. See the accordions below for details.

      ## HTTP Status Codes

      <AccordionGroup>
        <Accordion title="400 — Bad Request">
          | Exception class   | Error code    | When it occurs                                                                 | How to resolve                                                                       |
          | ----------------- | ------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
          | `BadRequestError` | `bad_request` | The request body or query parameters are malformed or missing required fields. | Double check the fields submitted to be sure of correct format and necessary fields. |
        </Accordion>

        <Accordion title="401 — Unauthorized">
          Token endpoint errors are returned as JSON in the response body. Corti API errors are returned in the `WWW-Authenticate` response header with no body. The header is not accessible from the exception directly; use `.WithRawResponse()` on the request if you need it.

          | Exception class     | Error code            | When it occurs                                                           | How to resolve                                                 |
          | ------------------- | --------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------- |
          | `UnauthorizedError` | `invalid_client`      | Client authentication failed. There is a problem with the client ID.     | Verify your `client_id` is correct.                            |
          | `UnauthorizedError` | `unauthorized_client` | Client authentication failed. There is a problem with the client secret. | Verify your `client_secret` is correct.                        |
          | `UnauthorizedError` | `invalid_token`       | The bearer token is invalid or has expired.                              | Re-authenticate to obtain a fresh token and retry the request. |
        </Accordion>

        <Accordion title="403 — Forbidden">
          | Exception class  | When it occurs                                                                                          | How to resolve                                                  |
          | ---------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
          | `ForbiddenError` | Accessing a resource (interaction, recording, transcript, document) that belongs to a different client. | Verify the resource ID was created by the authenticated client. |
        </Accordion>

        <Accordion title="404 — Not Found">
          | Exception class | Error code                                  | When it occurs                         | How to resolve                                                                                  |
          | --------------- | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
          | `NotFoundError` | `Invalid '{resource_name}' '{resource_id}'` | The requested resource does not exist. | Verify the ID and parent resource ID is correct and was created under the authenticated tenant. |

          <Note>
            Attempting to access a resource that belongs to a different OAuth client also returns a 404, not a 403. This is intentional. Returning a 403 would confirm that the resource exists, which is a security risk.
          </Note>
        </Accordion>

        <Accordion title="422 — Unprocessable Entity">
          | Exception class            | When it occurs             | How to resolve                                                                    |
          | -------------------------- | -------------------------- | --------------------------------------------------------------------------------- |
          | `UnprocessableEntityError` | Request validation failed. | Check `Body` for `Code`, `Description`, `HowToFix`, `Detail`, and `Cause` fields. |
        </Accordion>

        <Accordion title="429 — Too Many Requests">
          | Exception class           | When it occurs                                                                 | How to resolve                                                                                                  |
          | ------------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
          | `CortiClientApiException` | Rate limit exceeded after retries exhausted (default: 2 retries with backoff). | Reduce request frequency or contact [support](https://help.corti.app/) to discuss your rate limit requirements. |
        </Accordion>

        <Accordion title="500 — Internal Server Error">
          | Exception class       | When it occurs                                                                                               | How to resolve                                                                                                             |
          | --------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
          | `InternalServerError` | An unexpected error occurred on the Corti side. `Body` contains `Detail`, `Type`, `Status`, and `RequestId`. | Double check your request format and retry the request. If the issue persists, contact [support](https://help.corti.app/). |
        </Accordion>

        <Accordion title="502 — Bad Gateway">
          | Exception class   | When it occurs                                                                         | How to resolve                                                                        |
          | ----------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
          | `BadGatewayError` | A gateway error occurred. `Body` contains `Detail`, `Type`, `Status`, and `RequestId`. | Retry the request. If the issue persists, contact [support](https://help.corti.app/). |
        </Accordion>

        <Accordion title="503 — Service Unavailable">
          | Exception class           | When it occurs                          | How to resolve                                                                      |
          | ------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------- |
          | `CortiClientApiException` | The service is temporarily unavailable. | Retry with exponential backoff. Monitor the [status page](https://status.corti.ai). |
        </Accordion>

        <Accordion title="504 — Gateway Timeout">
          | Exception class       | When it occurs                                                                      | How to resolve                                                                        |
          | --------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
          | `GatewayTimeoutError` | The gateway timed out. `Body` contains `Detail`, `Type`, `Status`, and `RequestId`. | Retry the request. If the issue persists, contact [support](https://help.corti.app/). |
        </Accordion>
      </AccordionGroup>

      ## WebSocket APIs

      WebSocket errors from `/streams` and `/transcribe` surface as exceptions thrown by `ConnectAsync()` (with `Message` set to the server status code, e.g. `CONFIG_DENIED`, `CONFIG_MISSING`, `CONFIG_TIMEOUT`) or as typed events on the socket.

      <Tip>
        Every `CONFIG_*` server message also carries a `Reason` field with human-readable details behind the failure. Whether you can read it depends on how you connect:

        * **Default mode** (`stream.ConnectAsync(new StreamConfig { … })` / `transcribe.ConnectAsync(new TranscribeConfig { … })`): the SDK handles the handshake-phase and `CONFIG_*` messages internally. It throws from `ConnectAsync()` with just the bare code. The `Reason` is not exposed.
        * **[Manual mode](/sdk/dotnet/websockets#connecting-without-configuration)** (`ConnectAsync()` with no config): the raw message, including `msg.Reason`, flows through the `StreamConfigStatusMessage` / `TranscribeConfigStatusMessage` event. Subscribe **before** calling `ConnectAsync()` to catch handshake-phase events.
      </Tip>

      <Accordion title="`CONFIG_DENIED`">
        > You sent a config message, but it's invalid.

        | `reason` from server                                                                | Likely cause                                                                                                         | Fix                                                                                      |
        | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
        | `invalid language code: must be a valid BCP 47 language tag`                        | `transcription.primaryLanguage` is not a syntactically valid BCP-47 tag (e.g. `"english"`, `"en_US"`, empty string). | Use a [supported language code](https://docs.corti.ai/stt/languages).                    |
        | `invalid output locale: language should not be empty`                               | `mode.type: "facts"` without `mode.outputLocale` (or with an empty value).                                           | Set `mode.outputLocale` to a valid BCP-47 code whenever `mode.type` is `facts`.          |
        | `invalid output locale: invalid language code: must be a valid BCP 47 language tag` | `mode.type: "facts"` with a syntactically invalid `mode.outputLocale`.                                               | Use a [supported language code](https://docs.corti.ai/stt/languages) for `outputLocale`. |
        | `unknown mode`                                                                      | `mode.type` is not `transcription` or `facts`.                                                                       | Use one of the two supported values.                                                     |
        | `invalid participants`                                                              | Participant `role` outside `doctor` / `patient` / `multiple`.                                                        | Restrict to the three supported roles.                                                   |
        | `invalid audio format: MIME type not allowed...`                                    | `audioFormat` MIME type is not in the supported list.                                                                | Use a [supported MIME type](https://docs.corti.ai/stt/audio) or omit the field.          |
      </Accordion>

      <Accordion title="`CONFIG_MISSING`">
        > You sent a non-config frame before any valid `config` message arrived.

        Only reachable in [manual mode](/sdk/dotnet/websockets#connecting-without-configuration). Default mode sends config for you.

        | `Reason` from server                              | Cause                                                                                                                                                                                                                     | Fix                                                                                                                                                                                                                                             |
        | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
        | `No valid configuration provided for interaction` | A non-config frame reached the server before a config message. Typically a `Send(byte[], …)` audio call, or a `Send(StreamFlushMessage, …)` / `Send(StreamEndMessage, …)` call before any `Send(StreamConfigMessage, …)`. | Call `Send(new StreamConfigMessage { … }, …)` (or `TranscribeConfigMessage`) as the first frame after `ConnectAsync()` returns, **or** pass the config directly to `ConnectAsync(new StreamConfig { … })` and let the SDK handle the handshake. |
      </Accordion>

      <Accordion title="`CONFIG_TIMEOUT`">
        > The 10-second handshake window elapsed without any `config` message arriving.

        Only reachable in [manual mode](/sdk/dotnet/websockets#connecting-without-configuration). The default handshake sends config well within the 10s budget.

        | `Reason` from server                   | Cause                                                                    | Fix                                                                                                                                                                                                                                      |
        | -------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
        | `no configuration provided within 10s` | Server's 10s handshake timer expired without receiving a config message. | Call `Send(new StreamConfigMessage { … }, …)` (or `TranscribeConfigMessage`) immediately after `ConnectAsync()` returns, **or** pass the config directly to `ConnectAsync(new StreamConfig { … })` and let the SDK handle the handshake. |
      </Accordion>
    </Tab>

    <Tab title="REST API">
      **Resource and API errors** (all endpoints except the OAuth token endpoint) return JSON with `requestid`, `status`, `type`, `detail`, and `validationErrors` fields:

      ```json theme={null}
      {
        "requestid": "<string>",
        "status": 400,
        "type": "<string>",
        "detail": "<string>",
        "validationErrors": [
          {}
        ]
      }
      ```

      **Authentication errors** from the OAuth token endpoint return `error` and `error_description` fields:

      ```json theme={null}
      {
        "error": "invalid_client",
        "error_description": "Client authentication failed."
      }
      ```

      ## HTTP Status Codes

      <AccordionGroup>
        <Accordion title="400 — Bad Request">
          | Error code               | When it occurs                                                          | How to resolve                                                                                                         |
          | ------------------------ | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
          | `invalid_request`        | The request is missing a required parameter or is otherwise malformed.  | Ensure required fields (`grant_type`,`scope`) are present and correctly formatted.                                     |
          | `unsupported_grant_type` | The `grant_type` value is not recognised by the server.                 | This API requires a `grant_type` of `client_credentials`. Corti Assistant requires alternate methods for `grant_type`. |
          | `invalid_scope`          | The requested scope does not exist or is not permitted for this client. | Use a valid scope. This API requires `openid`.                                                                         |
        </Accordion>

        <Accordion title="401 — Unauthorized">
          Token endpoint errors are returned as JSON in the response body. Corti API errors are returned in the `WWW-Authenticate` response header with no body. Check the header directly if the response body is empty.

          | Error code            | When it occurs                                                                                           | How to resolve                                                 |
          | --------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
          | `invalid_client`      | Client authentication failed. There is a problem with the client ID.                                     | Verify your `client_id` is correct.                            |
          | `unauthorized_client` | Client authentication failed. There is a problem with the client secret                                  | Verify your `client_secret` is correct.                        |
          | `invalid_token`       | The bearer token is invalid or has expired. Check the `WWW-Authenticate` header for `error_description`. | Re-authenticate to obtain a fresh token and retry the request. |
        </Accordion>

        <Accordion title="403 — Forbidden">
          | When it occurs                                                                                          | How to resolve                                                  |
          | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
          | Accessing a resource (interaction, recording, transcript, document) that belongs to a different client. | Verify the resource ID was created by the authenticated client. |
        </Accordion>

        <Accordion title="404 — Not Found">
          | Error                                       | When it occurs                         | How to resolve                                                                                  |
          | ------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
          | `Invalid '{resource_name}' '{resource_id}'` | The requested resource does not exist. | Verify the ID and parent resource ID is correct and was created under the authenticated tenant. |
          | `'{resource_name}' not found`               | The requested resource does not exist. | Verify the ID and parent resource ID is correct and was created under the authenticated tenant. |
        </Accordion>

        <Accordion title="429 — Too Many Requests">
          You have exceeded the rate limit for the API. Retry the request after a delay, using exponential backoff. If the error persists, reduce request frequency or contact [support](https://help.corti.app/) to discuss your rate limit requirements.
        </Accordion>

        <Accordion title="500 — Internal Server Error">
          An unexpected error occurred on the Corti side. Double check your request format and retry the request. If the issue persists, contact [support](https://help.corti.app/).
        </Accordion>

        <Accordion title="503 — Service Unavailable">
          The service is temporarily unavailable. Retry with exponential backoff. Monitor the [status page](https://status.corti.ai).
        </Accordion>
      </AccordionGroup>

      ## WebSocket APIs

      WebSocket errors from `/streams` and `/transcribe` arrive as plain JSON messages on the socket: `{ type: "CONFIG_DENIED", reason: "…" }`, `{ type: "CONFIG_MISSING", reason: "…" }`, etc. Without an SDK in the middle, you see every server message verbatim, including the `reason` field on every `CONFIG_*` event.

      <Note>
        **The raw protocol is manual mode out of the box.** There's no SDK layer handling the handshake for you. You open the socket, send `{ type: "config", configuration: { … } }` yourself, and listen for `CONFIG_ACCEPTED` before sending audio. See the [Streams API reference](/api-reference/streams) for the full protocol.
      </Note>

      <Note>
        **The server does not close the socket on `CONFIG_DENIED` or `CONFIG_MISSING`.** Both codes reject the input but keep the connection open. Each subsequent non-config frame triggers a fresh `CONFIG_MISSING` response, one per frame, until the client closes the socket. SDK consumers don't see this because the SDK calls `close()` on rejection internally. Raw-protocol clients should close the socket themselves once they receive either rejection.
      </Note>

      <Accordion title="`CONFIG_DENIED`">
        > You sent a config message, but it's invalid.

        | `reason` from server                                                                | Likely cause                                                                                                         | Fix                                                                                      |
        | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
        | `invalid language code: must be a valid BCP 47 language tag`                        | `transcription.primaryLanguage` is not a syntactically valid BCP-47 tag (e.g. `"english"`, `"en_US"`, empty string). | Use a [supported language code](https://docs.corti.ai/stt/languages).                    |
        | `invalid output locale: language should not be empty`                               | `mode.type: "facts"` without `mode.outputLocale` (or with an empty value).                                           | Set `mode.outputLocale` to a valid BCP-47 code whenever `mode.type` is `facts`.          |
        | `invalid output locale: invalid language code: must be a valid BCP 47 language tag` | `mode.type: "facts"` with a syntactically invalid `mode.outputLocale`.                                               | Use a [supported language code](https://docs.corti.ai/stt/languages) for `outputLocale`. |
        | `unknown mode`                                                                      | `mode.type` is not `transcription` or `facts`.                                                                       | Use one of the two supported values.                                                     |
        | `invalid participants`                                                              | Participant `role` outside `doctor` / `patient` / `multiple`.                                                        | Restrict to the three supported roles.                                                   |
        | `invalid audio format: MIME type not allowed...`                                    | `audioFormat` MIME type is not in the supported list.                                                                | Use a [supported MIME type](https://docs.corti.ai/stt/audio) or omit the field.          |
      </Accordion>

      <Accordion title="`CONFIG_MISSING`">
        > You sent a non-config frame before any valid `config` message arrived.

        | `reason` from server                              | Cause                                                                                                                                                     | Fix                                                                                                                              |
        | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
        | `No valid configuration provided for interaction` | A non-config frame (binary audio, `{ type: "flush" }`, `{ type: "end" }`) reached the server before a `{ type: "config", configuration: { … } }` message. | Send the config message as the first frame after the WebSocket opens. Wait for `CONFIG_ACCEPTED` before sending any other frame. |
      </Accordion>

      <Accordion title="`CONFIG_TIMEOUT`">
        > The 10-second handshake window elapsed without any `config` message arriving.

        | `reason` from server                   | Cause                                                                    | Fix                                                                                    |
        | -------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
        | `no configuration provided within 10s` | Server's 10s handshake timer expired without receiving a config message. | Send `{ type: "config", configuration: { … } }` immediately after the WebSocket opens. |
      </Accordion>
    </Tab>
  </Tabs>
</div>
