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

# Erros e limites

> Como a API do Symphony comunica falhas, o que significa cada código de erro, quando tentar de novo e quais limites de uso existem.

## O que é

Esta página explica como a API do Symphony comunica falhas, o que significa cada código de erro, quando vale a pena tentar de novo e quais limites de uso existem. Use-a para montar o tratamento de erros da sua integração.

## 1. Como ler um erro

Toda resposta de erro tem status HTTP `4xx` ou `5xx` e um corpo JSON. O código estável do erro pode vir em **dois lugares diferentes**, conforme o endpoint.

<Tabs>
  <Tab title="Formato A: código em error">
    ```json theme={null}
    {
      "detail": "File not found",
      "error": {
        "code": "RESOURCE_NOT_FOUND",
        "message": "The content may have been deleted or moved.",
        "action": "Refresh the page. If the problem continues, contact support.",
        "retryable": false,
        "request_id": "req_a1b2c3"
      }
    }
    ```
  </Tab>

  <Tab title="Formato B: código em detail">
    Comum no chat, como modelo indisponível e limite de consumo.

    ```json theme={null}
    {
      "detail": {
        "code": "CONSUMPTION_LIMIT_REACHED",
        "message": "I can't answer this request. You will be able to use AI again on 01/11/2026.",
        "action": "If you need access before that date, contact an administrator to increase your limit.",
        "retryable": false,
        "request_id": "req_d4e5f6"
      }
    }
    ```
  </Tab>
</Tabs>

**Casos especiais, sem código:**

| Situação | Corpo |
| - | - |
| Limite de requisições por IP | `{ "detail": "Too many requests. Please try again.", "retry_after": 60 }` |
| Cota de tokens da empresa | `{ "detail": { "error": "quota_exceeded", "reset_at": "...", "used": 0, "limit": 0 } }` |
| Falha inesperada do servidor | Pode chegar sem corpo JSON. Trate como `UNKNOWN_ERROR` |

### Lendo o código com segurança

```python theme={null}
def codigo_do_erro(resposta):
    try:
        corpo = resposta.json()
    except ValueError:
        return "UNKNOWN_ERROR"

    detail = corpo.get("detail")
    if isinstance(corpo.get("error"), dict):
        return corpo["error"].get("code", "UNKNOWN_ERROR")
    if isinstance(detail, dict) and "code" in detail:
        return detail["code"]
    if isinstance(detail, dict) and detail.get("error") == "quota_exceeded":
        return "QUOTA_EXCEEDED"
    if resposta.status_code == 429:
        return "RATE_LIMITED"
    return "UNKNOWN_ERROR"
```

### Regras para programar contra os erros

* **Use o `code`, nunca o texto.** O `code` é estável. `message` e `action` podem ser reescritos a qualquer momento.
* **As mensagens são sempre em inglês.** A API não traduz. Se você mostra o erro para o seu usuário, traduza a partir do `code`.
* **`retryable`** diz se tentar de novo tem chance de funcionar.
* **Guarde o `request_id`** nos seus logs. É por ele que o time do Symphony encontra o que aconteceu.

## 2. Códigos de status HTTP

| Status | O que aconteceu | Tentar de novo? |
| -: | - | - |
| `400` | Corpo inválido, parâmetro que o modelo não aceita ou conteúdo grande demais | Não. Corrija a requisição |
| `401` | Chave inválida, revogada ou substituída. Também aparece quando falta permissão para criar algo | Não. Gere a chave de novo ou peça a permissão |
| `402` | Seu limite de consumo acabou, ou seu acesso foi bloqueado | Não. Só o administrador resolve, ou a virada do mês |
| `403` | Sem permissão para a ação, ou chave de API desativada no ambiente | Não |
| `404` | Recurso não existe, ou você não tem acesso a ele. Inclui modelo fora do catálogo | Não. Confira o ID e o `X-Enterprise-Id` |
| `409` | O agente existe, mas o modelo base dele foi removido | Não. O agente precisa ser corrigido na interface |
| `422` | Campo obrigatório faltando ou com tipo errado. O corpo traz a lista de campos em `detail` | Não |
| `429` | Muitas requisições, ou cota da empresa esgotada | Sim, depois de esperar |
| `5xx` | Falha temporária do Symphony ou do fornecedor de IA | Sim, com espera crescente |

<Note>
  Por segurança, um recurso que existe mas que você não pode ver responde `404`, e não `403`. Assim a API não revela a existência de dados de outras pessoas.
</Note>

## 3. Catálogo de códigos de erro

### Modelo e agente

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `MODEL_UNAVAILABLE` | O `model` não existe no catálogo da sua empresa ou você não tem acesso | Não | Envie o `X-Enterprise-Id` correto e copie o `id` de `GET /api/models` |
| `AGENT_BASE_MODEL_UNAVAILABLE` | O agente perdeu o modelo base | Não | Peça a quem administra o agente para escolher outro modelo base |
| `MODEL_TEMPORARILY_UNAVAILABLE` | O modelo não respondeu desta vez | Sim | Tente de novo ou use outro modelo |
| `INVALID_PARAMETER` | Um parâmetro (como `temperature`, `max_tokens` ou `stop`) está fora do que o modelo aceita. A `message` diz qual | Não | Ajuste ou remova o parâmetro |
| `INVALID_CONFIGURATION` | Falta informação na configuração do agente ou da conexão | Não | Fale com o administrador |
| `API_CREDENTIALS_INVALID` | As credenciais que o Symphony usa no fornecedor de IA estão com problema | Não | Fale com o administrador ou use outro modelo |
| `CONTEXT_LIMIT_EXCEEDED` | A pergunta, o histórico e os arquivos juntos passaram do que o modelo aguenta | Não | Reduza o conteúdo, resuma o histórico ou use um modelo com janela maior |
| `EMPTY_RESPONSE` | O modelo terminou sem gerar conteúdo | Sim | Tente de novo |

### Disponibilidade e rede

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `RATE_LIMITED` | Muitas requisições em pouco tempo, no Symphony ou no fornecedor de IA | Sim | Espere o `Retry-After` e tente de novo |
| `TIMEOUT` | O modelo demorou mais que o esperado | Sim | Tente de novo em alguns instantes |
| `NETWORK_ERROR` | A conexão caiu durante o envio | Sim | Tente de novo |
| `SERVICE_UNAVAILABLE` | O serviço não conseguiu atender agora | Sim | Tente de novo com espera crescente |
| `STREAM_INTERRUPTED` | O streaming terminou antes de a resposta acabar | Sim | Gere a resposta de novo |

### Consumo e cota

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `CONSUMPTION_LIMIT_REACHED` | Seu limite mensal de consumo acabou. A `message` traz a data de renovação | Não | Fale com o administrador para aumentar o limite, ou espere a renovação |
| `CONSUMPTION_BLOCKED` | Seu acesso à IA foi bloqueado pelo administrador | Não | Fale com o administrador |
| `QUOTA_EXCEEDED` | A cota de tokens da sua empresa acabou | Não, até a renovação | Espere a data em `reset_at` ou fale com o administrador |

### Acesso

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `AUTHENTICATION_REQUIRED` | A chave é inválida, foi revogada ou substituída | Não | Confira a chave e o header `Authorization: Bearer sk-...` |
| `PERMISSION_DENIED` | Sua conta não tem permissão para esta ação | Não | Peça a permissão ao administrador |
| `RESOURCE_NOT_FOUND` | O recurso não existe, foi apagado ou você não tem acesso | Não | Confira o ID e o `X-Enterprise-Id` |

### Arquivos e documentos

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `FILE_TOO_LARGE` | O arquivo passou do tamanho aceito | Não | Reduza o arquivo ou divida em partes |
| `FILE_FORMAT_UNSUPPORTED` | Formato não suportado | Não | Converta para um formato suportado (PDF, DOCX, TXT, por exemplo) |
| `FILE_CORRUPTED` | O arquivo está incompleto ou não abre | Não | Envie outra cópia |
| `FILE_PROCESSING_FAILED` | Não foi possível ler o conteúdo do arquivo | Sim | Tente de novo ou envie o arquivo em outro formato |
| `RETRIEVAL_FAILED` | O conteúdo anexado não pôde ser lido na hora da resposta | Sim | Tente de novo |

### Outros

| `code` | Significado | Repetir? | O que fazer |
| - | - | :-: | - |
| `UNKNOWN_ERROR` | Erro inesperado | Sim | Tente de novo. Se continuar, envie o `request_id` ao suporte |

## 4. Quando tentar de novo

**Tente de novo** quando `retryable` for `true`, ou quando o status for `429` ou `5xx`:

* Espere um tempo que **cresce a cada tentativa** (1 s, 2 s, 4 s, 8 s...) e acrescente uma pequena variação aleatória.
* Se a resposta trouxer o header `Retry-After`, espere **pelo menos** esse número de segundos.
* Limite o número de tentativas (por exemplo, 5) e registre a falha final com o `request_id`.

<Warning>
  **Nunca tente de novo** em `400`, `401`, `402`, `403`, `404`, `409` e `422`. Nenhum deles se resolve sozinho, e repetir só consome o seu limite de requisições.
</Warning>

```python theme={null}
import random
import time

def chamar_com_retry(fazer_requisicao, tentativas=5):
    for tentativa in range(tentativas):
        resposta = fazer_requisicao()
        if resposta.ok:
            return resposta
        if resposta.status_code not in (429, 500, 502, 503, 504):
            return resposta
        espera = float(resposta.headers.get("Retry-After", 2 ** tentativa))
        time.sleep(espera + random.uniform(0, 1))
    return resposta
```

## 5. Limites de uso

São limites **independentes**. Saber qual deles foi atingido evita tentativas inúteis.

| Limite | Valor atual | Contado por | Resposta |
| - | - | - | - |
| Requisições à API | 400 por minuto | Endereço IP de origem | `429`, com bloqueio de 60 s |
| Execuções de fluxo | 30 por minuto | Empresa | `429` |
| Transcrição de áudio | 30 por minuto | Empresa | `429` |
| Conversão de texto em fala | 30 por minuto | Empresa | `429` |
| Cota de tokens | Definida no contrato da empresa | Empresa | `429` com `quota_exceeded` |
| Limite de consumo | Definido pelo administrador, por mês | Usuário | `402` |

Os valores podem ser ajustados por ambiente.

### Limite de requisições por IP

Toda resposta traz headers para você acompanhar o limite:

| Header | Significado |
| - | - |
| `X-RateLimit-Limit` | Total permitido na janela |
| `X-RateLimit-Remaining` | Quanto ainda resta |
| `X-RateLimit-Reset` | Quando a janela recomeça |
| `Retry-After` | Só no `429`: quantos segundos esperar |

<Warning>
  **O limite é por IP, não por chave.** Várias integrações saindo pela mesma rede (mesmo servidor, mesmo NAT, mesmo runner de CI) dividem a mesma cota.
</Warning>

`GET /health` e `GET /api/version` não contam neste limite, e `GET /api/models` também não.

### Limite de consumo do usuário

É o teto de gasto mensal da conta dona da chave. Ele é verificado **antes** de qualquer chamada ao modelo, então uma requisição bloqueada não gera custo. Acompanhe com `GET /api/v1/consumption/me` (veja a [Referência da API](/desenvolvedores/api/referencia-da-api)).

### Tempo de resposta e tamanho

* **Configure timeouts generosos.** Respostas de modelos grandes, com muito contexto ou com arquivos, podem levar alguns minutos. Recomendamos ao menos **300 segundos** para a resposta completa. Se precisar de respostas rápidas, use streaming.
* **Arquivos:** o tamanho máximo de upload é definido pela configuração da sua empresa. Consulte o administrador se precisar enviar arquivos grandes.
* **Áudio:** arquivos acima de 25 MB são comprimidos automaticamente antes da transcrição.

## 6. Erros durante o streaming

Com `"stream": true`, o status `200 OK` é enviado **antes** de o modelo começar a responder. Se algo der errado no meio, a falha chega **dentro do fluxo**, como um evento JSON com o objeto `error`, e não como status HTTP de erro.

O evento de erro tem o mesmo conteúdo do formato B:

```
data: {"error": {"code": "STREAM_INTERRUPTED", "message": "...", "action": "...", "retryable": true, "request_id": "req_..."}}

data: [DONE]
```

Na sua leitura do streaming:

1. Para cada linha `data: {...}`, verifique se o JSON tem a chave `error` antes de ler `choices`.
2. Um `data: [DONE]` depois de um erro **não** significa sucesso. Considere a resposta como falha.
3. Se a conexão fechar sem `data: [DONE]`, trate como `STREAM_INTERRUPTED`.
4. Ignore linhas em branco.

## 7. Como pedir ajuda com um erro

Ao abrir um chamado, envie:

* O **`request_id`** da resposta de erro.
* O **endpoint** e o **horário** aproximado (com fuso horário).
* O **status HTTP** e o **`code`**.
* O corpo da requisição, **sem a chave de API**.

Os canais de suporte estão em [Ambientes e suporte](/desenvolvedores/api/ambientes-e-suporte).

## Documentos relacionados

* [Conectar via API](/desenvolvedores/api/conectar-api)
* [Criando projetos com a API](/desenvolvedores/api/projetos-com-a-api)
* [Referência da API](/desenvolvedores/api/referencia-da-api)
* [Ambientes e suporte](/desenvolvedores/api/ambientes-e-suporte)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.