Production error observability
Making a.js:1:4523 useful again
Making production failures actionable with uploaded source maps, a same-origin Sentry tunnel, contextual errors, filtering, and replay.
4 min readBy Abdullah Raheel
Two ways to lose the failure
We had two separate blind spots. Received errors pointed to minified code such as a.js:1:4523 because source maps were missing. Other events never arrived because direct requests to sentry.io could be blocked.
These were independent failures. Source maps determine whether a received stack can be symbolicated. Transport determines whether the event reaches Sentry at all. Fixing only one still leaves the incident unreadable or invisible.
Upload source maps without publishing them
@sentry/nextjs wrapped the build with withSentryConfig. CI supplied SENTRY_AUTH_TOKEN, SENTRY_ORG, and SENTRY_PROJECT. The build plugin uploaded the maps, widened client-file upload for better traces, and used deleteSourcemapsAfterUpload so those maps were not served from the public output.
export default withSentryConfig(nextConfig, {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
sourcemaps: {
disable: process.env.NODE_ENV === 'development',
deleteSourcemapsAfterUpload: true
},
widenClientFileUpload: true,
disableLogger: true,
tunnelRoute: '/t'
})That kept symbolication inside the normal deployment build. There was no separate sentry-cli upload command for an engineer to remember after the release.
Use the application origin as the transport
The first same-origin endpoint was /monitoring, but blockers still matched it. I shortened the route to /t. Browser events then targeted the application origin, and the Next.js server forwarded them to Sentry.
The original rollout recorded full capture after that change. That was a result from the rollout window, not a promise that every blocker or network will always deliver every event.
A silent toolchain mismatch needed its own fix
Next.js 15 moved browser setup into instrumentation-client.ts. With Turbopack enabled, the project remained on Sentry v9 and source-map upload stopped without an obvious application failure. Moving to Sentry v10 restored the compatible upload path.
The application also initialized Sentry across browser, server, and edge runtimes and added route-level and global error boundaries. Symbolication was a build concern; capturing React, request, and runtime failures was a separate application concern.
Readable does not automatically mean useful
A beforeSend hook added page path, browser information, viewport, and an application-version tag. It categorized API, timeout, and network failures and filtered known Twilio calling restrictions before ingestion.
Session Replay sampled 5% of normal sessions and every error session in production. Tracing initially ran at 100% in staging and 10% in production, then was disabled when it consumed too much quota. Sampling is an operating setting, not a value to copy blindly.
- Upload private source maps during the build.
- Send browser events through a same-origin tunnel.
- Separate expected product restrictions from application failures.
- Attach route and replay context so a readable line number also has user-flow context.

