Skip to content

Sentry SDK setupExpressErrorHandler isn't capturing bare exceptions on POST /flowsheet #1367

@jakebromberg

Description

@jakebromberg

Problem

Investigation under BS#1271 surfaced two observability gaps that are independent of the root-cause controller fix:

Gap 1 — setupExpressErrorHandler didn't capture a bare TypeError

The POST /flowsheet burst captured under BS#1271 produced 8 spans with http.response.status_code: 500 and span.status: internal_error, but zero matching captured exceptions in the Sentry errors dataset. The errorHandler is wired correctly:

  • apps/backend/app.ts:150Sentry.setupExpressErrorHandler(app, { shouldHandleError: shouldCaptureExpressError })
  • apps/backend/app.ts:151app.use(errorHandler) (centralized handler that emits a 500 for non-WxycError)
  • apps/backend/middleware/sentryErrorFilter.tsshouldCaptureExpressError returns true for any non-LmlClientError with missing / NaN / ≥500 statusCode

A bare TypeError has no statusCode, so the filter resolves to true. The SDK should have captured. It didn't.

The "Mirror: create_entry failed" capture on POST /flowsheet (backend@v0.1.507, 2026-06-08) shows Sentry.captureException works in this transaction — so the gap is specific to setupExpressErrorHandler's express-middleware path, not Sentry's transport.

SDK: @sentry/node ^10.53.1.

Gap 2 — user.* attributes empty on http.server spans

All 8 failing http.server spans return empty for user.id, user.username, user.email, user.ip even though every failing request carried a JWT and went through requirePermissions. The user/ DJ attribution that would have let us identify the affected DJ's session is missing.

Why this matters

Together these gaps mean: when a 5xx code path doesn't have an explicit Sentry.captureException, the failure mode shows up as a span-only signal with no user attribution and no exception detail. Diagnosing BS#1271 required reading raw spans + correlating against existing tests; with the SDK working as documented, the bare TypeError would have surfaced as a typed Sentry issue immediately.

Next steps (suggested)

  1. Reproduce setupExpressErrorHandler skipping a bare TypeError on Express 5 async-handler with @sentry/node ^10.53.1. The shouldHandleError option name may be silently deprecated in v10; check the SDK changelog / source.
  2. If the SDK no longer honors shouldHandleError: either re-implement the LmlClientError filter as beforeSend, or stop relying on auto-capture and add explicit Sentry.captureException at controller boundaries that do 5xx.
  3. Investigate why http.server spans don't carry user.* attributes. Probably needs an httpIntegration({ requestHook }) to read req.auth?.id and tag the span / scope.

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    concern:observabilitySentry, breadcrumbs, audit reports, time-series views

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions