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

# Erros do GraphQL

> Como a API GraphQL do Ayrshare informa erros, desde códigos de status HTTP em requisições malformadas até o array errors, sucesso parcial, novas tentativas idempotentes e limites de taxa.

<h2 id="resolver-errors-arrive-with-http-200">
  Erros de resolver chegam com HTTP 200
</h2>

Esta é a coisa mais importante a saber antes de escrever o tratamento de erros.

Seguindo a especificação GraphQL over HTTP, uma requisição que chega aos nossos resolvers retorna **HTTP 200 mesmo quando uma operação falhou**. A falha é informada dentro do corpo da resposta, e não pelo código de status.

Portanto, esta verificação não funciona:

```javascript theme={"system"}
// ERRADO - tratará uma requisição com falha como sucesso
if (response.ok) {
  return "everything worked";
}
```

Em vez disso, verifique o corpo. Alguns erros de transporte, como o 415 para um `Content-Type` não suportado, têm o corpo vazio, então verifique se a resposta é JSON antes de fazer o parsing:

```javascript theme={"system"}
if (!response.headers.get("content-type")?.includes("json")) {
  throw new Error(`GraphQL request failed with HTTP ${response.status}`);
}

const result = await response.json();

if (result.errors) {
  for (const error of result.errors) {
    // Erros capturados antes da execução não têm extensions, então leia com segurança.
    console.log(error.message, error.extensions?.status);
  }
}
```

Algumas falhas são capturadas antes de qualquer execução. Nenhuma delas chega a um resolver nem consome uma chamada de API:

<ul class="custom-bullets">
  <li>Uma requisição malformada retorna um status de erro: <strong>HTTP 400</strong> para JSON inválido ou ausência de <code>query</code>, <strong>413</strong> para um corpo acima de 64 KB, <strong>405</strong> para um método diferente de <code>POST</code> e <strong>415</strong> para um <code>Content-Type</code> não suportado.</li>
  <li>Uma consulta que não é válida para o schema retorna <strong>HTTP 400</strong> somente se sua requisição enviar <code>Accept: application/graphql-response+json</code>. Isso abrange erro de sintaxe, campo desconhecido, tipo de argumento incorreto, valor de enum inválido e uma consulta acima dos <a href="/docs/apis/graphql/limits#query-limits">limites de consulta</a>. Se você enviar <code>Accept: application/json</code>, ou nenhum cabeçalho <code>Accept</code>, o mesmo erro retorna <strong>HTTP 200</strong>. Em ambos os casos, o corpo tem um array <code>errors</code> e nenhum <code>data</code>.</li>
</ul>

Depois que a execução começa, a validação de entrada no nível do resolver e as falhas da API — incluindo autenticação, autorização, limites de taxa upstream e respostas 5xx upstream — retornam HTTP 200 com um array `errors`.

<h2 id="the-error-shape">
  O formato do erro
</h2>

Todo erro de resolver carrega seu status de API equivalente ao HTTP em `extensions`:

```json theme={"system"}
{
  "data": { "postHistory": null },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["postHistory"],
      "extensions": {
        "status": 429,
        "retryAfter": 7
      }
    }
  ]
}
```

<ul class="custom-bullets">
  <li><code>message</code> — uma descrição legível por humanos. Removemos API Keys e outras credenciais das mensagens de erro dos resolvers, mas um erro sobre um valor que você enviou, como uma variável do tipo errado, pode repetir esse valor. Trate <code>message</code> como possivelmente sensível antes de registrá-la em logs.</li>
  <li><code>path</code> — qual campo da sua consulta falhou. Com vários campos em uma requisição, é assim que você identifica qual deles.</li>
  <li><code>extensions.status</code> — o status HTTP que a chamada REST equivalente teria retornado. Use-o para decidir o tratamento.</li>
  <li><code>extensions.code</code> — o código de erro numérico do Ayrshare, quando o endpoint subjacente fornece um.</li>
  <li><code>extensions.retryAfter</code> — presente em respostas 429 de cota ou limite de taxa upstream quando há um intervalo de nova tentativa disponível. Não está presente no 429 do orçamento de despacho por requisição.</li>
</ul>

Use `extensions.code` com a [referência de códigos de erro](/docs/errors/overview) ou passe-o para `explainError`.

<h2 id="partial-success">
  Sucesso parcial
</h2>

Se uma requisição pede várias coisas e apenas algumas têm sucesso, você recebe **tanto** `data` quanto `errors`:

```graphql theme={"system"}
{
  history: postHistory(lastDays: 7)
  analytics: socialAnalytics(platforms: [INSTAGRAM])
}
```

```json theme={"system"}
{
  "data": {
    "history": { "history": [{ "id": "RkQ8uXg2jT7bNd1Wq0Ya", "status": "success", "post": "Hello world" }], "refId": "9d2a7c41f0b8e6d35a1c", "count": 1, "lastUpdated": "2026-09-24T12:00:00.000Z", "nextUpdate": "2026-09-24T12:00:00.000Z" },
    "analytics": null
  },
  "errors": [
    {
      "message": "Rate limit exceeded",
      "path": ["analytics"],
      "extensions": { "status": 429 }
    }
  ]
}
```

`history` teve sucesso e seus dados podem ser usados. Apenas `analytics` precisa de nova tentativa. Não descarte a resposta inteira porque `errors` está presente — isso jogaria fora dados pelos quais você já foi cobrado.

<h2 id="partial-success-on-multi-network-posts">
  Sucesso parcial em publicações para várias redes
</h2>

Uma publicação para várias redes pode ter sucesso em algumas e falhar em outras. Isso **não** é informado como um erro GraphQL, porque a operação em si funcionou — ela fez exatamente o que você pediu e está informando o que aconteceu.

O resultado separa os três desfechos:

```graphql theme={"system"}
mutation {
  createPost(input: {
    post: "Hi"
    platforms: [FACEBOOK, INSTAGRAM]
    idempotencyKey: "multi-network-hi-001"
  }) {
    status
    postIds { platform postUrl }
    errors { platform message code }
    blocked { platform message }
  }
}
```

<ul class="custom-bullets">
  <li><code>postIds</code> — redes que publicaram, com as URLs das publicações. Apenas sucessos.</li>
  <li><code>errors</code> — redes que falharam, com o motivo.</li>
  <li><code>blocked</code> — redes interrompidas antes de uma tentativa, por exemplo pelo circuit breaker por rede após falhas determinísticas repetidas. Elas são separadas das tentativas junto ao provedor que retornaram erros.</li>
</ul>

`status` é `"error"` se **qualquer** rede falhou, então não é um sinal confiável de que nada foi publicado. Leia `postIds` para descobrir o que foi.

<h2 id="retries">
  Novas tentativas
</h2>

**A API GraphQL nunca faz novas tentativas automaticamente.** Se uma requisição falhar, nada foi tentado novamente em silêncio em seu nome.

Isso importa principalmente para mutations. `createPost` expõe `idempotencyKey`: gere uma chave única antes da primeira tentativa e, depois, reutilize a mesma chave e um payload idêntico em cada nova tentativa. Uma nova tentativa já resolvida reproduz o resultado original em vez de repetir a escrita. Não troque para uma nova chave após uma resposta ambígua.

`boostFacebookPost` e `instagramBoostPost` também recebem um `idempotencyKey`, e ele protege dinheiro de verdade. Uma nova tentativa com a mesma chave e os mesmos argumentos retorna o resultado original, marcado com `idempotentReplayed: true`, em vez de criar e pagar por um segundo anúncio. Uma chave cobre sua conta inteira nas duas plataformas da Meta, então nunca reutilize a chave de um boost do Facebook para um boost do Instagram.

Quando uma chave é recusada, `extensions.status` informa o motivo. `createPost` retorna 409 enquanto a primeira tentativa ainda está sendo processada, então aguarde e tente novamente com a mesma chave, e 400 quando o payload difere do da primeira tentativa. As mutations de boost retornam 409 em ambos os casos e também quando a chave foi usada para um boost na outra plataforma.

Outras escritas, como `addComment`, não têm chave de idempotência. Se a resposta delas se perder, verifique a rede social ou o estado da API antes de decidir se outra tentativa é segura.

Dois limites diferentes informam 429, e eles exigem tratamentos diferentes. O orçamento de despacho só rejeita campos raiz depois que cinco chamadas de API já foram iniciadas na mesma requisição, e sua mensagem começa com `Query exceeds the per-request dispatch budget`: divida esses campos em requisições de no máximo cinco, sem necessidade de aguardar. Qualquer outro 429 é um limite de taxa ou de cota: aguarde `extensions.retryAfter` segundos quando estiver presente; caso contrário, aplique um backoff antes de tentar novamente, e tente novamente apenas os campos que falharam. Para um 5xx em uma **leitura**, tentar novamente é seguro, com uma exceção: `generatePost` é uma query, mas uma nova tentativa chama o gerador de IA de novo, conta como outra chamada de API e retorna um texto diferente. Para um 5xx em uma escrita sem idempotência, confirme se ela teve efeito antes de tentar novamente.

<h2 id="common-statuses">
  Status comuns
</h2>

| `extensions.status` | Significado | O que fazer |
| - | - | - |
| 400 | Entrada inválida rejeitada pela nossa API | Corrija a requisição; tentar novamente não ajudará |
| 401 | API Key ausente ou inválida | Verifique o cabeçalho `Authorization` |
| 402 | O plano não inclui este recurso | Verifique seu plano |
| 403 | Chave válida, mas sem permissão para esta ação | Verifique as Profile Keys e o plano |
| 404 | O que você solicitou não existe | Verifique o id |
| 409 | A chave de idempotência está em uso: a primeira requisição ainda está em execução, ou uma chave de boost foi usada com argumentos diferentes | Se a primeira requisição ainda estiver em execução, aguarde e tente novamente sem alterações; caso contrário, use uma nova chave para a nova operação |
| 429 | Limite de taxa, cota ou orçamento de despacho | Se a mensagem mencionar o orçamento de despacho, divida a requisição. Caso contrário, aguarde `retryAfter` ou aplique um backoff se ele estiver ausente |
| 500 | Algo deu errado do nosso lado | Tente novamente uma leitura (não `generatePost`, que é cobrado novamente); reutilize a mesma chave de idempotência quando suportado; caso contrário, verifique uma escrita antes de tentar novamente |

Erros gerados pelo próprio GraphQL antes da execução, como um campo desconhecido, um tipo de argumento incorreto ou um valor de enum inválido, não têm `extensions.status`. Eles retornam HTTP 400 ou 200 dependendo do seu cabeçalho `Accept`, conforme descrito acima. Eles significam que a própria consulta está errada, e nenhuma chamada de API foi feita ou cobrada.
