This was sitting in CogniPrep's next.config.mjs, and it had been sitting there long enough that nobody questioned it:
// OPTIMIZED: Reduced from true to false to decrease bundle size
// This was causing large proxy.js files by uploading too many source maps
widenClientFileUpload: false,
Two claims, one line of code. The first claim is wrong. The second one is about build output, not about what users download, and the two got conflated in a comment with the word OPTIMIZED in capitals, which is the single most effective way to stop a future reader from checking.
What the option actually controls
widenClientFileUpload tells the Sentry build plugin how widely to look for client source maps when it uploads them to Sentry. Narrow means roughly the page bundles. Wide means the rest of the client build output too, which on a Next.js app is where your framework and shared chunks live.
Uploading a source map to Sentry is a build-time POST to an API. It does not add a byte to anything a browser fetches. And whether a browser can even see your maps is decided by a completely different option, two lines below in the same block:
hideSourceMaps: true,
So the two settings were being traded against each other when they are not on the same axis at all. One governs what Sentry can read. The other governs what the public can read.
The cost showed up as a bug I could not fix
A RangeError from /dashboard in production arrived like this:
app:///dashboard:193:70
<minified pair, recursing, in the framework chunk>
Column 70 of line 193 of a minified bundle, and then two minified frames calling each other. A stack overflow where every frame is unresolved tells you a cycle exists and nothing whatsoever about which of your components is in it. An error thrown from inside a page component the same day mapped cleanly to its source file and line, which is what made the pattern obvious: the frames Sentry could resolve were the ones in the narrow upload, and the frames in the recursion were in chunks that had never been uploaded at all.
That is the bargain widenClientFileUpload: false was quietly making. Errors in your own page code stay readable. Errors in anything shared, which is exactly where infinite loops and framework-level failures live, become coordinates in a file you do not have.
- widenClientFileUpload: false,
+ widenClientFileUpload: true,
The real price of turning it back on is build time and upload time. That is a number I can look at in a build log and decide about. "Bundle size" was not a number, it was a guess written in the imperative mood.
Check the premise yourself, in two commands
You do not need our repository to verify that source maps are not part of what we ship. Pull a chunk off the live site and look at its last line:
curl -s https://cogniprep.app/ | grep -o '/_next/static/chunks/[a-zA-Z0-9._-]*\.js' | sort -u | head -8
Then fetch any of those and check the tail for a sourceMappingURL comment. I ran it over the first eight chunks on the homepage, 36,292 bytes through to 249,109 bytes, and every one of them came back with no source map comment at all. Ask for the map directly and you get nothing either:
curl -s -o /dev/null -w "%{http_code}\n" https://cogniprep.app/_next/static/chunks/0ow3e8dcm8tp6.js.map
404
Nine bytes of 404 body. That is hideSourceMaps: true doing its job, and it is the proof that the option above it could never have been shrinking anything a visitor downloads. (Chunk names are content hashed, so copy a live one out of the first command rather than reusing mine.)
The lesson I actually took from it
The specific option is replaceable; every project has its own equivalent. The transferable part is that a configuration comment asserting a benefit is a claim with no test behind it, and it gets more load-bearing the longer it survives. This block of config has already produced one published post's worth of findings in this codebase, including a key whose own type definition says it has no effect under Turbopack, and the pattern is the same each time: options get set from a blog post, annotated with a benefit nobody measured, and then defended by the annotation.
Two commands and a 404 were enough to settle this one.
The app that this config builds is at cogniprep.app, where 56 providers' worth of timed assessment practice generates exactly the kind of production error that needs a readable stack trace. The chunks in the commands above are the ones serving its homepage right now.
Top comments (0)