Códigos de error
Cómo se ve un error de la API de AstrApp y qué significa cada código. Úsalo para decidir si corriges la petición o reintentas.
Formato del error
La mayoría de las rutas responde los errores con esta forma.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request body",
"details": [
{ "field": "name", "message": "String must contain at least 2 character(s)" },
{ "field": "archetype", "message": "Required" }
],
"request_id": "req_mfc2k9x1_4h7q2za",
"timestamp": "2026-09-22T10:30:00.000Z"
}
}codees estable: decide con él, no conmessage.detailssolo aparece en algunos errores; en los de validación trae un objeto por campo.request_ididentifica la petición en los registros del servidor. Inclúyelo si escribes a soporte.
Códigos estándar
| Código | HTTP | Qué significa |
|---|---|---|
BAD_REQUEST | 400 | La petición no se puede procesar: JSON inválido o un dato que la ruta rechaza. |
VALIDATION_ERROR | 400 | Uno o más campos no pasan la validación. details dice cuáles. |
UNAUTHORIZED | 401 | Falta autenticación, o la key es inválida, venció o está desactivada. |
FORBIDDEN | 403 | Estás autenticado, pero el recurso no es tuyo o tu cuenta no cumple un requisito. |
NOT_FOUND | 404 | El recurso no existe o no pertenece a tu organización. |
CONFLICT | 409 | El recurso ya existe o choca con su estado actual. |
UNPROCESSABLE_ENTITY | 422 | Los datos son válidos, pero no cumplen una regla de negocio. |
RATE_LIMIT_EXCEEDED | 429 | Pasaste el límite de peticiones de la ruta. |
INTERNAL_ERROR | 500 | Error inesperado del servidor. |
EXTERNAL_SERVICE_ERROR | 502 | Falló un servicio externo (proveedor de LLM, Hugging Face, Together…). |
SERVICE_UNAVAILABLE | 503 | La función no está disponible o no está configurada en este momento. |
Qué reintentar
Límite de peticiones
Un 429 trae el header Retry-After con los segundos que debes esperar. El cuerpo no incluye request_id:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"details": [
{ "message": "Rate limit exceeded. Retry after 42000ms" }
],
"timestamp": "2026-09-22T10:30:00.000Z"
}
}Qué rutas tienen límite y de cuánto está en Endpoints.
Casos con formato propio
Estas respuestas las arma la ruta directamente y no siempre siguen el formato de arriba.
| HTTP | Código | Cuándo |
|---|---|---|
| 403 | plan_limit_reached | Llegaste al máximo de datasets o conversaciones de tu plan. Trae current, limit y upgrade_url. |
| 403 | PLAN_CONVERSATIONS_LIMIT | Pediste generar más conversaciones de las que permite tu plan por trabajo. |
| 403 | PLAN_REQUIRED | La función exige un plan superior, como la descarga de adapters. |
| 409 | OFFER_UNAVAILABLE | La oferta de GPU ya no tiene precio vigente. Vuelve a buscar ofertas. |
| 503 | NOT_CONFIGURED | El proxy de /chat no está configurado. |
| 503 | QUERY_TIMEOUT | Filtrar las conversaciones o los items de un dataset tardó demasiado para su tamaño. Agrega un filtro más específico (búsqueda o estado) o procésalo por partes. |
En plan_limit_reached el código viene en el campo error como texto, no dentro de un objeto:
{
"error": "plan_limit_reached",
"message": "Has alcanzado el límite de 2 datasets de tu plan. Actualiza para continuar.",
"current": 2,
"limit": 2,
"upgrade_url": "/billing/plans"
}PLAN_REQUIRED llega como { "error": "<mensaje>", "code": "PLAN_REQUIRED", "requiredPlan": "professional" }, y algunas rutas de Opik responden { "success": false, "error": { "message", "code" } }. Para no depender de la forma, busca el código en error.code, luego en code y, si error es texto, en error.
Un 404 con una key válida no siempre es un id equivocado