Saltar a contenido

ADR-0003 · Errores SAP se propagan al filtro global, no se envuelven a mano

  • Estado: aceptado
  • Decisores: equipo OMS (iniciativa de observabilidad)
  • Fecha de la decisión: julio 2026

Contexto y problema

Cada servicio envolvía los errores del Service Layer a su manera (new BadRequestException(mensaje interpolado)): se perdía el stack y la causa original, la lógica de traducción estaba duplicada, los 4xx se descartaban en el beforeSend de Sentry y el referenceId que veía el usuario no era correlacionable con ningún log. Diagnosticar un error de producción exigía reproducirlo.

Opciones consideradas

  1. Filtro global SapErrorFilter + excepción de dominio con cause — elegida
  2. Seguir envolviendo por servicio, con una convención documentada
  3. Interceptor que traduzca todos los errores SAP a un catálogo fijo

Decisión

Ante un error de SAP no se captura ni se envuelve a mano: se deja subir al SapErrorFilter global, que responde con formato uniforme, correlaciona por X-Request-Id (aceptado o generado por requestIdMiddleware, tag request_id en GlitchTip, prefijo [rid:…] en logs) y captura con fingerprint por [errorCode, ruta]. Cuando hace falta un código de dominio se lanza SapBusinessException.fromSapError(error, codigo), que preserva la causa. Los background jobs usan captureJobError(...) explícito porque no pasan por el filtro HTTP.

Consecuencias

Positivas

  • Un error de producción se rastrea end-to-end con un solo ID (respuesta → GlitchTip → logs).
  • Sin duplicación de lógica de traducción; el stack original se preserva siempre.

Negativas / deuda asumida

  • Requiere disciplina: un try/catch con throw new BadRequestException(...) reintroduce el problema silenciosamente (regla documentada en AGENTS.md).
  • El filtrado de ruido queda centralizado en beforeSend de instrument.ts; tocarlo mal puede volver a descartar errores reales.