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

# Erros

> Trate o *APIError no SDK Go: status, código e mensagem, errors.As e errors.Is, os códigos próprios do SDK, as constantes Code, novas tentativas, timeouts e rate limits.

Toda falha da API, de rede ou local é de um único tipo: `*squarecloud.APIError`. Inspecione-o com `errors.As`.

```go theme={"system"}
package main

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/squarecloudofc/sdk-api-go/v3"
)

func main() {
	ctx := context.Background()
	c := squarecloud.New(os.Getenv("SQUARECLOUD_API_KEY"))
	appID := "abc123def456abc123def456"

	err := c.Apps.Start(ctx, appID)

	var apiErr *squarecloud.APIError
	if errors.As(err, &apiErr) {
		fmt.Println(apiErr.Status, apiErr.Code, apiErr.Message)
		fmt.Println(apiErr.Method, apiErr.Path) // "POST" "/v2/apps/<id>/start"
	}
}
```

## `APIError`

| Campo     | Tipo     | Descrição                                                                                                                               |
| --------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `Status`  | `int`    | Status HTTP. `0` quando nenhuma resposta chegou (erro de rede, timeout, verificação local)                                              |
| `Code`    | `string` | O código de erro da API, por exemplo `APP_NOT_FOUND`, ou um dos códigos do SDK. Compare-o com as [constantes `Code*`](#constantes-code) |
| `Message` | `string` | A explicação do servidor. `""` quando o servidor enviou apenas um código                                                                |
| `Method`  | `string` | Método HTTP da chamada que falhou                                                                                                       |
| `Path`    | `string` | Caminho da URL da chamada que falhou, sem a query string                                                                                |

`Unwrap()` retorna a causa (o erro de transporte, de decodificação ou do context) para `NETWORK_ERROR`, `TIMEOUT` e JSON inválido, ou `nil`. `Error()` gera `squarecloud: <METHOD> <path>: HTTP <status> <CODE>: <message>`, sem `HTTP <status>` quando o status é `0` e sem `: <message>` quando ela está vazia. Compare pelos campos, não por esse texto.

### Contexts cancelados e expirados

Uma chamada cujo `ctx` é cancelado retorna um `*APIError` com `NETWORK_ERROR`, e uma cujo prazo expira retorna `TIMEOUT`, ambos com status `0`. Eles fazem unwrap para o erro do context:

```go theme={"system"}
_, err := c.Apps.Get(ctx, appID)

switch {
case errors.Is(err, context.Canceled):
	// you canceled ctx
case errors.Is(err, context.DeadlineExceeded):
	// the deadline of ctx, or the default one, passed
}
```

Algumas falhas não são `*APIError`:

* [`Realtime.Next`](/pt-br/sdks/go/realtime#encerrando-o-stream) retorna o `ctx.Err()` puro quando seu `ctx` termina, e `io.EOF` quando o stream termina normalmente.
* Problemas do lado de quem chama são erros simples: um reader de upload `nil`, uma URL de snapshot ou URL base que não pode ser interpretada, uma entrada que o `encoding/json` não consegue codificar e um erro do `io.Writer` passado para `DownloadSnapshot`.

## Códigos do SDK

| Status   | Código            | Constante           | Quando                                                                                                                                                                                            |
| -------- | ----------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0        | `NETWORK_ERROR`   | `CodeNetworkError`  | Sem resposta (DNS, conexão reiniciada, corpo cortado), ou `ctx` cancelado. O erro original está em `Unwrap()`                                                                                     |
| 0        | `TIMEOUT`         | `CodeTimeout`       | Sem resposta antes do prazo (veja [Timeouts](/pt-br/sdks/go/client#timeouts))                                                                                                                     |
| 0        | `FILE_TOO_LARGE`  | `CodeFileTooLarge`  | Verificação local: um upload acima de 100 MB ou um `Files.Write` acima de 10 MB. Nada foi enviado                                                                                                 |
| 0        | `INVALID_ID`      | `CodeInvalidID`     | Verificação local: um id vazio, `.` ou `..`. Nada foi enviado                                                                                                                                     |
| 0        | `INVALID_API_KEY` | `CodeInvalidAPIKey` | Verificação local: o cliente foi criado com uma chave vazia. Toda chamada, exceto `Service.Status`. Apenas no SDK Go                                                                              |
| qualquer | `UNKNOWN_ERROR`   | `CodeUnknown`       | Uma resposta sem código (como uma página de erro de proxy), com o `Status` real e a mensagem `HTTP <status>`. Um corpo 2xx que não é JSON tem a mensagem `Invalid JSON in HTTP <status> response` |

## Constantes `Code*`

`Code` é uma `string` simples. O pacote tem uma constante por código público da API, nomeada a partir dele no estilo Go (`CodeAppNotFound` para `APP_NOT_FOUND`, `CodeInvalidID`, `CodeDNSFailed`, ...), além dos códigos próprios do SDK acima.

A lista de códigos da API cresce. **Trate um código desconhecido pelo seu status HTTP**:

```go theme={"system"}
func handle(err error) error {
	var apiErr *squarecloud.APIError
	if !errors.As(err, &apiErr) {
		return err
	}

	switch apiErr.Code {
	case squarecloud.CodeAppNotFound:
		return nil
	case squarecloud.CodeContainerAlreadyStarted:
		return nil // fine
	}
	switch {
	case apiErr.Status == 429:
		return retryLater()
	case apiErr.Status >= 500:
		return reportOutage(apiErr)
	}
	return err
}
```

## Erros de qualquer chamada

| Status | Código                  | Quando                                                                                                                 |
| ------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| 401    | `ACCESS_DENIED`         | Chave de API ausente, desconhecida, revogada ou expirada                                                               |
| 403    | `MISSING_SCOPE`         | A chave não tem o escopo desta chamada. `Message` o informa                                                            |
| 403    | `RESOURCE_NOT_ALLOWED`  | A chave está limitada a outras aplicações ou bancos de dados                                                           |
| 403    | `PERMISSION_DENIED`     | Seu cargo no workspace não permite a ação                                                                              |
| 404    | `ROUTE_NOT_FOUND`       | Rota desconhecida                                                                                                      |
| 429    | `RATE_LIMITED`          | Bloqueio de conta, chave ou IP (pode durar cerca de 30 min), e o limite dos endpoints de rede e de `Account.Snapshots` |
| 429    | `KEEP_CALM`             | Rápido demais para esta rota                                                                                           |
| 500    | `INTERNAL_SERVER_ERROR` | Erro no servidor                                                                                                       |
| 503    | `DATABASE_UNAVAILABLE`  | O banco de dados da plataforma está indisponível. Uma mutação pode já ter sido aplicada                                |

## Códigos da API por grupo

<AccordionGroup>
  <Accordion title="Não encontrado">
    `APP_NOT_FOUND`, `DATABASE_NOT_FOUND`, `WORKSPACE_NOT_FOUND`, `MEMBER_NOT_FOUND`, `FILE_NOT_FOUND`, `SNAPSHOT_NOT_FOUND`, `REPOSITORY_NOT_FOUND`, `BRANCH_NOT_FOUND`, `ROUTE_NOT_FOUND`
  </Accordion>

  <Accordion title="Validação">
    `INVALID_ACCESS_TOKEN`, `INVALID_AUTORESTART`, `INVALID_BRANCH_LENGTH`, `INVALID_CODE`, `INVALID_CONTENT`, `INVALID_CONTENT_TYPE`, `INVALID_DATABASE_TYPE`, `INVALID_DATABASE_VERSION`, `INVALID_DESCRIPTION`, `INVALID_DISPLAY_NAME`, `INVALID_DOMAIN`, `INVALID_ENCODING`, `INVALID_ENV_CONTENT`, `INVALID_FILE`, `INVALID_FILENAME`, `INVALID_FILTER`, `INVALID_GROUP`, `INVALID_ID`, `INVALID_INPUT`, `INVALID_JSON_BODY`, `INVALID_MEMORY`, `INVALID_NAME`, `INVALID_PARAMETERS`, `INVALID_PATH`, `INVALID_RESET_TYPE`, `INVALID_SCOPE`, `INVALID_SNAPSHOT_ID`, `INVALID_SUBDOMAIN`, `INVALID_TIME_RANGE`, `INVALID_VERSION_ID`, `MISSING_PARAMETERS`, `MISSING_REQUIRED_FIELDS`, `NO_UPDATE_DATA`, `VALIDATION_FAILED`, `VALIDATION_TIMEOUT`, `ENV_NAME_TOO_LONG`, `ENV_CONTENT_TOO_LONG`, `TOO_MANY_ENV_VARS`, `RESERVED_DOMAIN`, `CANNOT_SET_SUBDOMAIN`, `STATIC_APP_ENV_NOT_SUPPORTED`
  </Accordion>

  <Accordion title="Autenticação e permissões">
    `ACCESS_DENIED`, `MISSING_SCOPE`, `RESOURCE_NOT_ALLOWED`, `PERMISSION_DENIED`, `SCOPE_NOT_GRANTABLE`, `BLOCKED_PATH`, `UPGRADE_REQUIRED`
  </Accordion>

  <Accordion title="Limites e rate limits">
    `RATE_LIMITED`, `KEEP_CALM`, `APPLICATIONS_LIMIT_REACHED`, `WORKSPACE_LIMIT_REACHED`, `MEMBERS_LIMIT_REACHED`, `LOAD_BALANCER_LIMIT_REACHED`, `DAILY_SNAPSHOTS_LIMIT_REACHED`, `INSUFFICIENT_MEMORY`, `FILE_TOO_LARGE`, `PAYLOAD_TOO_LARGE`, `REALTIME_MAX_CONNECTIONS`, `REALTIME_MAX_CONNECTIONS_APP`, `AI_DAILY_LIMIT_REACHED`, `AI_MAX_CONCURRENT_STREAMS`, `AI_NO_PLAN_LIMIT_REACHED`
  </Accordion>

  <Accordion title="Containers (start, stop, restart)">
    `CONTAINER_ALREADY_STARTED`, `CONTAINER_ALREADY_STOPPED`, `CONTAINER_TEMPORARILY_SUSPENDED`, `CONTAINER_NOT_FOUND`, `CONTAINER_INSUFFICIENT_DISK_SPACE`, `CONTAINER_NETWORK_CONFLICT`, `ACTION_FAILED`, `DATABASE_NOT_RUNNING`
  </Accordion>

  <Accordion title="Uploads, arquivos e commits">
    `UPLOAD_BUSY`, `UPLOAD_FAILED`, `UPLOAD_ABORTED`, `STORAGE_UPLOAD_FAILED`, `COMMIT_FAILED`, `READ_FAILED`, `SAVE_FAILED`, `RENAME_FAILED`, `DELETE_FAILED`, `REQUEST_ABORTED`, `EMPTY_RESPONSE`
  </Accordion>

  <Accordion title="Snapshots">
    `SNAPSHOT_FAILED`, `SNAPSHOT_PROCESSING`, `SNAPSHOT_RESTORE_FAILED`, `SNAPSHOT_DATABASE_MISMATCH`, `RESTORE_IN_PROGRESS`
  </Accordion>

  <Accordion title="Deploys e GitHub">
    `GIT_ALREADY_CONFIGURED`, `GIT_NOT_CONFIGURED`, `GITHUB_NOT_CONNECTED`, `REPOSITORY_BRANCH_ALREADY_CONFIGURED`, `REPOSITORY_NOT_AVAILABLE`, `REPOSITORY_PERMISSION_REQUIRED`, `FAILED_TO_FETCH`
  </Accordion>

  <Accordion title="Rede e domínios">
    `ANALYTICS_BUSY`, `UNABLE_TO_FETCH_ANALYTICS`, `UNABLE_TO_FETCH_ERRORS`, `UNABLE_TO_FETCH_PERFORMANCE`, `DNS_FAILED`, `DOMAIN_ALREADY_EXISTS`, `NO_CUSTOM_DOMAIN`, `PURGE_CACHE_FAILED`, `LOGS_UNAVAILABLE`, `METRICS_NOT_SUPPORTED`
  </Accordion>

  <Accordion title="Bancos de dados e workspaces">
    `DATABASE_CREATION_FAILED`, `DATABASE_UNAVAILABLE`, `RESET_FAILED`, `WORKSPACE_CREATION_FAILED`, `APP_ALREADY_IN_WORKSPACE`, `MEMBER_ALREADY_ADDED`, `CANNOT_EDIT_OWNER`, `CANNOT_INVITE_OWNER`, `CANNOT_LEAVE_OWNER`, `CONFLICTING_RESOURCES`
  </Accordion>

  <Accordion title="Plataforma">
    `INTERNAL_SERVER_ERROR`, `CLUSTER_MAINTENANCE_TRY_LATER`, `CLUSTER_SELECTION_FAILED`, `CLUSTER_TIMEOUT`, `CLUSTER_UNAVAILABLE`, `AI_UNAVAILABLE`
  </Accordion>

  <Accordion title="Depreciados">
    `CodeRateLimit` (`RATE_LIMIT`) e `CodeRateLimitExceeded` (`RATE_LIMIT_EXCEEDED`) ainda são exportados, marcados como depreciados: a API agora responde `RATE_LIMITED` (`CodeRateLimited`) para ambos.
  </Accordion>
</AccordionGroup>

Os erros de `AI.Chat` usam, em vez disso, códigos da OpenAI em minúsculas (`access_denied`, `rate_limit_exceeded`, `server_overloaded`, ...), que `Code` carrega literalmente. Veja [IA](/pt-br/sdks/go/ai#erros).

## Novas tentativas

O SDK só tenta novamente o que é seguro repetir, até `WithMaxRetries` vezes (padrão `2`, ou seja, até 3 tentativas):

| Repetido                   | Métodos                                                                               |
| -------------------------- | ------------------------------------------------------------------------------------- |
| `NETWORK_ERROR`            | Apenas `GET` (incluindo aberturas de realtime e `DownloadSnapshot` antes da resposta) |
| 503 `UPLOAD_BUSY`          | Qualquer método                                                                       |
| 503 `ANALYTICS_BUSY`       | Qualquer método                                                                       |
| 503 `DATABASE_UNAVAILABLE` | Apenas `GET`                                                                          |

Ele **nunca** tenta novamente:

* `TIMEOUT`;
* qualquer **429**: `RATE_LIMITED` pode ser um bloqueio de cerca de 30 minutos, e `KEEP_CALM` também não é repetido;
* outros 5xx;
* erros de IA.

O 503 `DATABASE_UNAVAILABLE` pode chegar depois que uma mutação já foi aplicada, então o SDK não o repete fora de `GET`. Repita suas próprias mutações idempotentes se precisar. Um upload só é repetido quando seu corpo pode ser reenviado: um `io.ReaderAt` com tamanho conhecido, como um `*os.File` (veja [Commit e upload](/pt-br/sdks/go/commit_and_upload#entradas-aceitas)).

A espera antes da nova tentativa `n` (começando em 0) é `min(8 s, 500 ms · 2^n) · U(0.5, 1)`: backoff exponencial com jitter de 50% a 100%. Defina `WithMaxRetries(0)` para desativar as novas tentativas.

## Timeouts

`WithTimeout` (30 s) se aplica apenas quando o `ctx` não tem prazo, e um único prazo cobre a chamada inteira, incluindo as novas tentativas e as esperas de backoff. Veja [Timeouts](/pt-br/sdks/go/client#timeouts) para as chamadas com mínimo de 2 minutos e as chamadas sem prazo padrão. Um prazo que expira retorna `TIMEOUT` com status `0`, nunca é repetido e faz unwrap para `context.DeadlineExceeded`.

## Rate limits

Toda conta tem um limite de requisições a cada 60 segundos, definido pelo seu plano ([valores](/pt-br/api-reference/limitations-and-restrictions)), e algumas rotas têm limites próprios:

* **429 `RATE_LIMITED`**: um bloqueio da conta, da chave de API ou do IP, que pode durar cerca de 30 minutos. Também é o limite dos endpoints de rede e de `Account.Snapshots`.
* **429 `KEEP_CALM`**: chamadas demais a uma rota em pouco tempo.

O SDK nunca repete um 429. Diminua o ritmo e aguarde antes de tentar novamente.
