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¶
- Filtro global
SapErrorFilter+ excepción de dominio concause— elegida - Seguir envolviendo por servicio, con una convención documentada
- 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/catchconthrow new BadRequestException(...)reintroduce el problema silenciosamente (regla documentada enAGENTS.md). - El filtrado de ruido queda centralizado en
beforeSenddeinstrument.ts; tocarlo mal puede volver a descartar errores reales.