When Everything Works in Office, but Breaks in Client’s Server
Recently I faced an interesting bug when deploying a Next.js project.
On our office server, everything worked perfectly. But when the same Docker image was deployed in our client’s environment, the app broke — static chunks could not be loaded.
The Symptom
My app uses a dynamic route like:
app/feature/[work_id]/listing/page.tsx
So Next.js generates static chunks with an encoded path like:
/_next/static/chunks/app/feature/%5Bwork_id%5D/listing/page-xxxxx.js
But in the client’s server, I noticed requests were being made to:
/_next/static/chunks/app/feature/%5bwork_id%5d/listing/page-xxxxx.js
Spot the difference? %5B
vs %5b
.
Both are technically valid encodings of [
but they are not the same string.
Why Did This Happen?
It turned out to be related to their load balancer.
- URL encoding is case-insensitive (
%5B
=%5b
=[
). - But depending on the load balancer/proxy settings, hex characters can be normalized into lowercase.
In my office environment, the load balancer kept it uppercase.
In the client environment, it forced lowercase.
The Impact
Next.js expected chunks at %5Bwork_id%5D
, but the request came in as %5bwork_id%5d
.
Result: the chunk was not found, and the page broke.
The Fix
I added a simple middleware in Next.js to normalize the path:
if (url.pathname.includes('%5b') || url.pathname.includes('%5d')) {
const normalizedPath = url.pathname
.replace(/%5b/g, '%5B')
.replace(/%5d/g, '%5D');
url.pathname = normalizedPath;
return NextResponse.rewrite(url);
}
This way, any lowercase %5b
or %5d
is rewritten back to uppercase, and Next.js can resolve the chunks.
🛠 Debug with cURL
After fixing the encoding in middleware (replacing %5b → %5B and %5d → %5D), I try to verify whether the chunk is correctly served.
curl -v http://localhost:5000/_next/static/chunks/app/feature/%5bworkd_id%5d/listing/%5bdocument_id%5d/extraction/page-638a1fa4c352c07e.js
-v → verbose mode, shows both headers and body.
If the fix is correct, will should see a
200 OK
response with headers like:
HTTP/1.1 200 OK
Content-Type: application/javascript; charset=utf-8
Cache-Control: public, max-age=31536000, immutable
…and the body will be minified JavaScript.
- If the response is
404 Not Found
, the chunk is still not being resolved correctly (likely an encoding issue remains).
Lessons Learned
- Bugs are not always in your code — infra can surprise you.
- URL encoding might look trivial, but consistency matters when loading static chunks.
- Next.js middleware can be a lifesaver for defensive fixes like this.
Have you ever faced a similar environment-only
bug? I’d love to hear your story.
Top comments (0)