Pular para o conteúdo principal

Tratamento de Erros

Todos os erros da API seguem o mesmo formato base, o ApiError, independentemente do endpoint, método HTTP ou status. Isso permite tratamento programático sem parsing de mensagens.

Breaking change

Versões anteriores retornavam erros de validação como dicionário {"field": ["mensagem"]} e itens de sync com falha como string em error. Agora toda resposta de erro traz um array errors[] de objetos ApiError no mesmo formato.

Como funciona

Toda resposta de erro contém um array errors[]. Cada item desse array é um ApiError que carrega no mínimo dois campos: type (categoria programática) e message (texto descritivo).

{
"success": false,
"message": "Turma 'ALG001-2099.1' não encontrada.",
"errors": [
{
"type": "not_found",
"message": "Turma 'ALG001-2099.1' não encontrada.",
"entity": "enrollment",
"code": "ALG001-2099.1"
}
]
}

Os campos extras (entity, code, field, rule, etc.) variam conforme o type. A tabela abaixo é a principal ferramenta de decisão: olhe o type, identifique a categoria e os campos esperados.

typeHTTPQuando acontece
validation_failed422Schema do request inválido (campo obrigatório ausente, formato errado)
code_not_foundsync (200/207/422) ou 404Code referenciado não existe (ex: turma com subject_code inexistente)
constraint_violationsync (200/207/422) ou 422Regra de negócio violada (ex: turma sem nenhum curso vinculado)
not_found404Recurso buscado por code não existe
authentication_failed401 ou 403API Key ausente, inválida, desativada ou com scope insuficiente
rate_limit_exceeded429Limite de requisições por minuto atingido
internalsync (200/207/422) ou 500Falha inesperada do servidor. Em sync, o item falhado vai para data.errors[]. Fora de sync, vira HTTP 500

Em endpoints de sincronização (*/sync), o status HTTP reflete o resultado do lote: 200 se todos os itens passaram, 207 se alguns passaram e outros falharam, 422 se nenhum item foi persistido. Veja Status HTTP do sync em lote.

Em que parte da resposta os erros aparecem

A localização do errors[] depende do cenário. Há dois lugares possíveis:

Na raiz da resposta: o request inteiro falhou. Vale para validação (422), 404, single-item (422), autenticação (401/403) e rate limit (429).

Em data.errors[]: o request foi aceito e processado item a item (sync em lote). Cada item que falhou vira um objeto com index, code e seu próprio errors[]. O status HTTP varia conforme o resultado do lote (200/207/422) e success é true quando ao menos um item foi persistido. Veja Status HTTP do sync em lote.

Exemplo de falha em endpoint single (errors na raiz)

{
"success": false,
"message": "Turma 'ALG001-2025.1' ou aluno 'ALU2024999' não encontrado.",
"errors": [
{
"type": "not_found",
"message": "Turma 'ALG001-2025.1' ou aluno 'ALU2024999' não encontrado.",
"entity": "enrollment",
"code": "ALG001-2025.1"
}
]
}

Status HTTP do sync em lote

Endpoints de sincronização (*/sync) processam cada item de forma independente, então o status HTTP reflete o resultado do lote como um todo:

SituaçãoHTTPsuccess
Todos os itens passaram200true
Alguns passaram e outros falharam (parcial)207true
Houve falhas e nenhum item foi persistido422false

Em todos os casos, a resposta traz data.created, data.updated, data.failed e, quando há falhas, data.errors[] com o detalhe de cada item. Independente do status, sempre verifique data.failed para saber quais itens não passaram. Não trate apenas 200 como sucesso: um 207 significa que parte do lote foi sincronizada.

Sync com falhas parciais

Quando um endpoint de sincronização processa um batch, cada item é tratado individualmente. Os que dão certo entram em created ou updated; os que falham entram em data.errors[]. Uma falha parcial retorna HTTP 207 (success: true); se nada for persistido, retorna 422 (success: false).

{
"success": true,
"data": {
"created": 8,
"updated": 1,
"failed": 1,
"errors": [
{
"index": 2,
"code": "ALG001-2025.1",
"errors": [
{
"type": "code_not_found",
"message": "Professores não encontrado(a)s: PROF999, PROF888",
"entity": "professor",
"missing": ["PROF999", "PROF888"]
}
]
}
]
}
}

index é a posição do item no array enviado (0-based) e code é o identificador do item.

Dois níveis de errors

Existem dois arrays chamados errors em níveis diferentes:

  • data.errors[] (externo): a lista de itens do batch que falharam. Sempre tem o mesmo tamanho que failed.
  • data.errors[N].errors[] (interno): a lista de falhas daquele item específico. Um único item pode acumular múltiplos erros quando tem várias referências inválidas ao mesmo tempo.

Em vez de reportar uma falha por vez, a API acumula tudo e devolve junto. Acumulação por item se aplica a:

  • Turma: subject_code + course_codes + professor_codes + student_codes (até 4 erros)
  • Gestor de Área: area_codes + unit_code (até 2 erros)
  • Curso: area_code + unit_code (até 2 erros)

Batch misto: sucessos e falhas convivem

O exemplo abaixo envia 3 itens onde o 1º e o 3º falham e o 2º é criado normalmente:

{
"success": true,
"data": {
"created": 1,
"updated": 0,
"failed": 2,
"errors": [
{
"index": 0,
"code": "GEST_A",
"errors": [
{ "type": "code_not_found", "message": "Áreas não encontrado(a)s: AX, AY", "entity": "area", "missing": ["AX", "AY"] },
{ "type": "code_not_found", "message": "Unidade 'UX' não encontrado(a).", "entity": "unit", "code": "UX" }
]
},
{
"index": 2,
"code": "GEST_C",
"errors": [
{ "type": "code_not_found", "message": "Unidade 'UY' não encontrado(a).", "entity": "unit", "code": "UY" }
]
}
]
}
}

Note que index: 1 não aparece porque foi sucesso. Use index para mapear cada falha de volta ao item original que você enviou.

Cenários comuns

Os blocos abaixo mostram um exemplo de cada categoria de erro.

Referência completa de campos

Cada type carrega um conjunto específico de campos contextuais além de type e message. A tabela é a referência canônica.

typeCampos contextuais
validation_failedfield (dot-notation)
code_not_found (um code)entity, code
code_not_found (múltiplos)entity, missing[]
constraint_violationentity, rule, invalid_codes[] (quando aplicável)
not_foundentity, code
authentication_failed (scope)rule, required_scope, client_scope
authentication_failed (auth)rule
rate_limit_exceededrule, limit, retry_after
internalexception_class

Regras de negócio (constraint_violation)

O campo rule permite identificar a regra violada sem parsear a mensagem.

ruleEndpointSignificado
at_least_one_professor/enrollments/syncItem sem professor_codes
at_least_one_course/enrollments/sync, /coordinators/syncItem sem course_codes
at_least_one_area/area-managers/syncItem sem area_codes
enrollment_without_courses/enrollments/sync, POST /enrollments/{code}/students/{code}Turma sem cursos vinculados
user_suspended/sso/generate-tokenUsuário com suspended_at não nulo

Regras de autenticação e rate limit

ruleHTTPSignificado
unauthenticated401Header Authorization ausente
invalid_api_key401API Key não corresponde a nenhum cliente
api_key_disabled403API Key existe mas está desativada no painel
insufficient_scope403Scope da API Key não permite a operação
rate_limit_exceeded429Limite de requisições por minuto atingido