Saltar al contenido principal

Reference · Errores

Códigos HTTP que la API de Neuroon puede devolver y la estructura del body. La mayoría de respuestas vienen del GlobalExceptionHandler (api/src/main/java/.../rest/GlobalExceptionHandler.java); las excepciones se documentan abajo.

Envoltura estándar

{
"timestamp": "2026-05-06T10:15:00",
"status": 400,
"error": "Bad Request",
"message": "field-level error joined with commas",
"path": "/api/widget/search"
}

Generada en GlobalExceptionHandler.java:147-156.

CampoTipoNotas
timestampstringLocalDateTime.now().toString() (servidor en UTC, sin zona explícita).
statusnumberCódigo HTTP.
errorstringReason phrase del status (Bad Request, Unauthorized, …).
messagestringDetalle. En 400 incluye errores de validación concatenados con , .
pathstringRuta sin el prefijo uri= que añade WebRequest.

Códigos HTTP que emite el handler global

StatusExcepción Java que lo disparaSignificado
400 Bad RequestMethodArgumentNotValidException, ConstraintViolationException, MissingServletRequestParameterException, IllegalStateException, IllegalArgumentExceptionValidación fallida (@Valid, @RequestParam ausente, regla de dominio).
401 UnauthorizedBadCredentialsExceptionCredenciales inválidas.
403 ForbiddenAccessDeniedExceptionToken no autorizado para el recurso.
404 Not FoundResponseStatusException(NOT_FOUND) lanzada desde un controllerRecurso inexistente (shopId, producto).
500 Internal Server ErrorException (catch-all)Excepción no controlada. Reportar con timestamp y path.
502 Bad GatewayPaymentGatewayExceptionStripe inaccesible.
503 Service UnavailableCallNotPermittedException (circuit breaker abierto)Proveedor externo en estado abierto. Reintentar con backoff.

Otros status (405, 409, 415, …) los emite Spring por defecto sin pasar por el handler — el body llega con la envoltura estándar de Spring ({ timestamp, status, error, path }) sin message.

Casos especiales (envoltura distinta)

429 Too Many Requests — rate limit

Lo emiten los filtros (WidgetRateLimitFilter, RateLimitFilter), no el handler global. La envoltura es distinta:

{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again later.",
"retryAfter": 60,
"limit": 200,
"remaining": 0,
"timestamp": "2026-05-06T10:15:00Z"
}

Construido en WidgetRateLimitFilter.java:90-93. Headers asociados: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining. Ver Rate Limits.

401 / 403 desde ApiKeyAuthenticationFilter

Cuando la Shop API Key falla la validación, el filtro de autenticación emite directamente sin pasar por el handler global:

{
"error": "Invalid or missing X-Shop-API-Key header",
"status": 401
}

En ApiKeyAuthenticationFilter.java:131. Mismo formato cuando el origen no está autorizado pero con status: 403.

Validation errors (400)

MethodArgumentNotValidException y ConstraintViolationException se concatenan en message con formato field: descripción:

{
"timestamp": "2026-05-06T10:15:00",
"status": 400,
"error": "Bad Request",
"message": "products[0].externalId: must not be blank, products[0].price: must be positive",
"path": "/api/plugin/shops/123/products/sync"
}

GlobalExceptionHandler.java:22-47.

Buenas prácticas

  • No parsees el message con regex — el formato no es estable.
  • Reintenta sólo en 429, 502, 503 con backoff exponencial + jitter.
  • No reintentes en 400, 401, 403, 404 — son fallos del cliente.
  • Loguea timestamp, path y, si lo tienes, el requestId para correlacionar con el lado servidor cuando abras un ticket.
  • Diferencia las dos envolturas — la mayoría usa { timestamp, status, error, message, path }; rate-limit y filtros de auth usan formatos propios.

Próximas lecturas