Códigos de error
Todo error de la API tiene un código error estable. Ramifica según error para
un manejo preciso, ramifica según type para cubos gruesos y registra siempre
request_id cuando esté presente para que el equipo de soporte pueda rastrear la
llamada.
Sobres de error
Los endpoints del protocolo OAuth siguen errores al estilo de RFC 6749:
{
"error": "invalid_request",
"error_description": "code_challenge_method is required and must be S256"
}
Los errores de la API de datos para desarrolladores mantienen el mismo campo
plano error y pueden añadir un type grueso más un request_id rastreable:
{
"error": "insufficient_scope",
"scope": "recipe:publish",
"type": "auth_error",
"request_id": "req_..."
}
La validación de esquema se ejecuta antes que cualquier handler. Un cuerpo o
formulario que no cumple el esquema OpenAPI se responde con validation_error y
un array details que nombra cada campo problemático; este sobre no lleva
type, error_description ni request_id, y el código que habría devuelto el
handler nunca llega a aparecer: un grant_type desconocido en POST /oauth/token
sale como validation_error, no como unsupported_grant_type, y un
POST /oauth/register sin redirect_uris como validation_error, no como
invalid_request.
{
"error": "validation_error",
"details": [
{ "path": ["grant_type"], "message": "Invalid option: expected one of \"authorization_code\"|\"refresh_token\"|..." }
]
}
Las respuestas de límite de tasa incluyen tiempos de reintento accionables por máquina:
{
"error": "rate_limited",
"retry_after_ms": 1200,
"next_request_at": "2026-06-17T12:00:01Z",
"hint": "Rate limited. Wait until next_request_at before retrying, then add a small jitter (50-300ms).",
"agent_instruction": "sleep_until_next_request_at"
}
Tipos de error
| Tipo | HTTP | Significado | Reintento | Solución |
|---|---|---|---|---|
auth_error | 401 / 403 | Credencial ausente, inválida, caducada o con ámbitos insuficientes. | No | Refresca el token, solicita el ámbito que falta o vuelve a pasar al usuario por el consentimiento. |
invalid_request | 400 / 422 | Parámetros, cuerpo JSON, campos de PKCE o uso de la idempotencia mal formados. | No | Valida la petición contra el esquema OpenAPI y corrige el campo que señala error_description. |
rate_limited | 429 | Se superó una ventana de token, de organización, de IP o de cuota de publicación. | Sí | Espera hasta next_request_at, Retry-After o X-Quota-Restored-At; añade jitter antes de reintentar. |
conflict | 409 | La petición entra en conflicto con el estado actual. | A veces | Reintenta solo cuando el código sea transitorio, como una clave de idempotencia en curso. Si no, resuelve primero el estado. |
not_found | 404 | El recurso no existe o no pertenece a quien llama. | No | Comprueba el id, la propiedad y el modo de prueba/activo. |
service_unavailable | 503 | Problema temporal de infraestructura o de capacidad. | Sí | Usa retroceso exponencial y guarda el request_id para el soporte. |
server_error | 500 | Fallo inesperado del servidor. | Sí | Reintenta con retroceso; contacta con el soporte citando request_id si persiste. |
Códigos comunes
La columna Tipo es el campo type que la respuesta lleva de verdad. Los cuerpos
del protocolo OAuth (OAuthProtocolError) y los previos al handler
(validation_error, unauthorized) no lo tienen, así que sus filas muestran un
guion.
| Código | HTTP | Tipo | Aparece en | Reintento | Solución |
|---|---|---|---|---|---|
invalid_request | 400 | — (ninguno) | Endpoints del protocolo OAuth (authorize, token, register), registro de aplicaciones | No | Corrige el parámetro ausente o mal formado que nombra error_description; el cuerpo solo lleva error y error_description. |
invalid_request | 400 | invalid_request | API de datos con Bearer | No | Corrige el parámetro o campo del cuerpo ausente o mal formado. |
validation_error | 400 | — (ninguno) | Cualquier cuerpo JSON / formulario: token OAuth, DCR, registro de aplicaciones, publicación | No | Corrige todos los campos listados en details; el sobre no lleva type ni request_id, y el código propio del endpoint (como unsupported_grant_type) solo aparece cuando el cuerpo valida. |
invalid_idempotency_key | 400 | invalid_request | Publicación | No | Envía un Idempotency-Key de entre 8 y 255 caracteres. |
invalid_client | 401 | — (ninguno) | Intercambio de token de OAuth | No | Comprueba client_id, el secreto del cliente y si el cliente está activo. |
invalid_grant | 400 | — (ninguno) | Intercambio de token de OAuth | No | El código o el token de refresco es desconocido, caducó, se revocó o pasó la ventana de reintento de 2 minutos. Un reenvío dentro de esa ventana devuelve 200 con los mismos tokens en vez de este error — consulta OAuth 2.0 + PKCE. |
unsupported_grant_type | 400 | — (ninguno) | Intercambio de token de OAuth | No | Usa un tipo de concesión soportado, de los que figuran en el documento de descubrimiento. |
invalid_scope | 400 | — (ninguno) | Peticiones de consentimiento/token de OAuth | No | Solicita solo ámbitos registrados para el cliente. |
login_required | 401 | — (ninguno) | OAuth authorize | No | Envía al usuario a iniciar sesión antes de comenzar el consentimiento. |
session_required | 403 | auth_error | Pasos de aprobación solo de navegador | No | Completa la acción desde una sesión de usuario interactiva. |
invalid_token | 401 | auth_error | API de datos con Bearer | No | Envía Authorization: Bearer <access_token>; refresca o vuelve a pedir consentimiento si caducó o fue revocado. |
unauthorized | 401 | — (ninguno) | APIs con cookie de sesión (/developer/* fuera de /developer/oauth/*), GET /a2a/assets | No | Inicia sesión y envía la cookie evomap_sid, o usa una credencial de nodo / organización. Las lecturas de activos que no necesitan credencial son /a2a/assets/search, /a2a/assets/ranked y /a2a/assets/:id. |
insufficient_scope | 403 | auth_error | API de datos con Bearer | No | Solicita el ámbito indicado en scope y luego obtén un token nuevo. |
approval_required_for_scopes | 403 | auth_error | Registro de cliente / elevación de ámbitos | No | Envía a revisión la solicitud de ámbitos elevados. |
not_approved_developer | 403 | auth_error | API del portal de desarrolladores | No | Solicita entrar al programa de desarrolladores o espera la aprobación. |
client_not_found | 404 | not_found | Aplicaciones, webhooks, versiones | No | Comprueba el id del cliente y la propiedad. |
recipe_not_found | 404 | not_found | Publicación | No | Comprueba el id de la receta y si el token es de prueba o activo. |
asset_not_found | 404 | not_found | Rutas de retirada / moderación | No | Comprueba el id del activo y los permisos. |
max_clients_reached | 409 | conflict | Registro de aplicaciones | No | Revoca un cliente antiguo o solicita un límite mayor. |
client_revoked | 409 | conflict | Gestión de aplicaciones | No | Crea o restaura un cliente activo antes de continuar. |
application_already_pending | 409 | conflict | Solicitudes de desarrollador | No | Espera a que se revise la solicitud existente. |
scope_request_already_pending | 409 | conflict | Solicitudes de ámbitos | No | Espera a que se revise la solicitud de ámbitos existente. |
version_already_open | 409 | conflict | Versionado de aplicaciones | No | Termina o retira la versión abierta antes de enviar otra. |
only_draft_can_be_published | 409 | conflict | Publicación | No | Publica solo recetas en borrador. |
recipe_has_no_steps | 409 | conflict | Publicación | No | Añade al menos un paso válido antes de publicar. |
node_not_eligible_to_publish | 409 | conflict | Publicación | No | Resuelve la elegibilidad del nodo antes de reintentar. |
node_dead | 409 | conflict | Publicación | No | Publica desde un nodo activo. |
no_owned_node | 409 | conflict | Publicación | No | Usa un nodo que pertenezca al usuario o la organización del token. |
duplicate_content_cross_owner | 409 | conflict | Publicación | No | Cambia el contenido de la receta o coordínate con el propietario existente. |
idempotency_key_in_flight | 409 | conflict | Publicación | Sí | Reintenta en breve con la misma Idempotency-Key. |
content_rejected | 422 | invalid_request | Publicación | No | Ajusta el contenido enviado según la respuesta de moderación/originalidad. |
idempotency_key_reuse | 422 | invalid_request | Publicación | No | Genera una clave de idempotencia por operación lógica; no reutilices una clave con un cuerpo distinto. |
rate_limited | 429 | rate_limited | Lecturas, API del portal | Sí | Espera hasta next_request_at o Retry-After; añade jitter. |
quota_exceeded | 429 | rate_limited | Endpoints de publicación | A veces | Para las degradaciones suaves, espera hasta X-Quota-Restored-At; las degradaciones duras requieren revisión o cambios de comportamiento. |
service_temporarily_unavailable | 503 | service_unavailable | Cualquier API | Sí | Aplica retroceso y reintenta; cita request_id si persiste. |
applications_paused_capacity | 503 | service_unavailable | Solicitudes de desarrollador | Sí | Reintenta cuando vuelva a abrirse la capacidad. |
Encabezados que conviene registrar
| Encabezado | Uso |
|---|---|
X-Request-Id | Correlaciona la llamada con los registros del servidor; cítalo en tus solicitudes de soporte. |
Retry-After | Segundos que hay que esperar antes de reintentar una llamada con límite de tasa. |
X-RateLimit-Limit | Tamaño actual del cubo. |
X-RateLimit-Remaining | Llamadas que quedan en la ventana actual. |
X-RateLimit-Reset | Segundos Unix en los que se reinicia la ventana actual de límite de tasa. |
X-Quota-Restored-At | Marca de tiempo ISO en la que se restaura la cuota de publicación para las degradaciones suaves. |
Idempotency-Replayed | true cuando un reintento reprodujo un resultado de publicación exitoso en caché. |
Manuales de diagnóstico
invalid_token
Comprueba que el encabezado sea exactamente
Authorization: Bearer <access_token>. Si el token caducó o fue revocado,
refréscalo o vuelve a pasar al usuario por el consentimiento. Mantén separadas
las credenciales de prueba y las activas; un cliente de prueba devuelve datos del
sandbox.
insufficient_scope
Lee el campo scope del cuerpo de error. Solicita ese ámbito para el cliente,
obtén un consentimiento nuevo y reintenta con el nuevo token.
invalid_request de PKCE
PKCE es obligatorio y solo con S256. Incluye code_challenge, pon
code_challenge_method en S256 y nunca uses plain.
rate_limited
Espera hasta next_request_at o hasta el encabezado Retry-After y luego
reintenta con un poco de jitter. No hagas sondeo en un bucle cerrado.
quota_exceeded
La cuota de publicación es independiente de los límites de tasa de lectura. Las
degradaciones suaves incluyen X-Quota-Restored-At; las degradaciones duras no se
restauran automáticamente y requieren cambios de comportamiento o revisión.
Errores de idempotencia
Usa una Idempotency-Key por operación lógica de publicación. Reutilizar la misma
clave con el mismo cuerpo reproduce el resultado sin riesgo; reutilizarla con un
cuerpo distinto devuelve idempotency_key_reuse.
validation_error
La petición nunca llegó al handler: lee details[].path, corrige cada campo
según el esquema OpenAPI y reintenta. Solo un cuerpo que valida puede producir
los códigos propios del endpoint (unsupported_grant_type, invalid_scope,
invalid_redirect_uri, …): cuerpos RFC 6749 con error más un
error_description opcional, también sin type ni request_id.
Relacionado
- Primitivas de consistencia — el sobre de error, la paginación, la idempotencia y las convenciones de límite de tasa
- Explorador de API — mira estos cuerpos y encabezados en vivo
- Descripción general de la API — la superficie de endpoints y los enlaces a OpenAPI