Why Error Context Matters in Production: Fixing ERR-23
Why Error Context Matters in Production: Fixing ERR-23
Release: v0.1.124 · Track: Error Monitoring
The Problem
When something goes wrong in a production sanctions screening workflow, the first question is always: who was affected, what were they doing, and what route triggered the failure?
Until this issue was surfaced, the answer was: we don't know.
The captureError() utility in src/lib/capture-error.ts has always accepted a context argument, but that argument was never populated at any call site. Server-side catch blocks were calling it with no user or request metadata attached. The client-side global error listener was firing without a userId or sessionId in scope. Every error that reached the monitoring sink looked identical — a stack trace floating in a vacuum.
Why This Is a Real Risk
For a compliance platform, error context isn't a nice-to-have. Consider these scenarios:
- A fuzzy-match screening call fails silently for one user but not others. Without
userId, you cannot determine whether the failure is isolated or systemic. - An OFSI list sync error is logged at 03:00. Without
req.nextUrl.pathname, you cannot tell which API route or cron handler was responsible. - A support ticket arrives: "My screening result looked wrong last Tuesday." Without
sessionIdoractionmetadata on the error, you have no anchor for a log correlation query.
Debugging any of these today means joining ephemeral server logs by timestamp — a slow, error-prone process that does not scale.
The Remediation Plan
This release formalises the remediation approach, tied to the Sentry integration landing in ERR-22. Once Sentry is wired in, three changes close the gap:
1. Set user context at the API handler level
At the start of every authenticated API handler, identify the session and register it with Sentry before any business logic runs:
// src/app/api/screen/route.ts (example)
import * as Sentry from '@sentry/nextjs';
export async function POST(req: NextRequest) {
const session = await getServerSession(authOptions);
Sentry.setUser({ id: session?.user?.id });
try {
// ... screening logic
} catch (err) {
captureError(err, {
extra: {
userId: session?.user?.id,
path: req.nextUrl.pathname,
action: 'screen',
},
});
throw err;
}
}
This means every exception from that handler onwards carries the authenticated user's identity — no manual log correlation required.
2. Enrich captureException() call sites
Every catch block that calls into captureError() should pass a structured extra payload:
captureError(err, {
extra: {
userId,
path: req.nextUrl.pathname,
action, // e.g. 'ofsi-sync', 'fuzzy-match', 'export-pdf'
},
});
The action field is especially useful for the sanctions screening domain: it lets you filter errors by workflow step (list sync vs. screening request vs. PDF export) without relying on route paths alone.
3. Set user context on the client after session is established
In the client-side SessionProvider, call Sentry.setUser() once the session resolves so that any subsequent unhandled exceptions in the browser carry identity context:
// src/components/providers/session-provider.tsx (example)
useEffect(() => {
if (session?.user?.id) {
Sentry.setUser({ id: session.user.id });
} else {
Sentry.setUser(null); // clear on logout
}
}, [session]);
This covers browser-side failures in the monitoring dashboard and screening UI, where errors currently arrive anonymously.
What Stays the Same
The captureError() function signature is unchanged. The context parameter it already accepts will simply start being used. No breaking changes to existing call sites — they will continue to work, just without the enriched context until each site is updated.
Next Steps
| Task | Tracking |
|---|---|
| Integrate Sentry SDK | ERR-22 |
Update all server-side catch blocks with extra payload | ERR-23 |
Set Sentry.setUser() in SessionProvider | ERR-23 |
| Verify context appears in Sentry dashboard per-error | ERR-23 |
Once ERR-22 and ERR-23 are both resolved, any production error on the platform will carry enough context to identify the affected user, the route, and the action — turning a multi-hour debugging session into a targeted five-minute investigation.