[GH-ISSUE #263] Bug: External rewrite proxy causes ERR_CONTENT_DECODING_FAILED in browser #67

Closed
opened 2026-05-06 12:36:58 +02:00 by BreizhHardware · 0 comments

Originally created by @17hz on GitHub (Mar 5, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/263

Description

When using rewrites in next.config.ts to proxy requests to an external backend, the browser fails with ERR_CONTENT_DECODING_FAILED (net error).

Root Cause

Node.js fetch() automatically decompresses response bodies (gzip, br, deflate), but proxyExternalRequest (in config-matchers.ts) and __proxyExternalRequest (inlined in app-dev-server.ts) forward the upstream content-encoding and content-length headers as-is to the browser.

The browser sees content-encoding: gzip and attempts to decompress the body again, but it has already been decompressed by Node — resulting in ERR_CONTENT_DECODING_FAILED.

Reproduction

// next.config.ts
const nextConfig: NextConfig = {
  rewrites: () => [
    {
      source: "/api/:path*",
      destination: `${process.env.BACKEND_URL}/api/:path*`,
    },
  ],
};

Any request to /api/... that returns a gzip-compressed response from the backend will fail in the browser.

Expected Behavior

The proxy should strip content-encoding and content-length from the upstream response headers before forwarding to the browser, since Node fetch() has already decompressed the body.

Suggested Fix

In both proxyExternalRequest (config-matchers.ts) and __proxyExternalRequest (app-dev-server.ts), filter out content-encoding and content-length when building response headers:

upstreamResponse.headers.forEach((value, key) => {
  const lk = key.toLowerCase();
  if (!HOP_BY_HOP_HEADERS.has(lk) && lk !== "content-encoding" && lk !== "content-length") {
    responseHeaders.append(key, value);
  }
});

Environment

  • vinext: 0.0.21
  • Node.js: v22
  • Browser: Chrome
Originally created by @17hz on GitHub (Mar 5, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/263 ## Description When using `rewrites` in `next.config.ts` to proxy requests to an external backend, the browser fails with `ERR_CONTENT_DECODING_FAILED` (net error). ## Root Cause Node.js `fetch()` automatically decompresses response bodies (gzip, br, deflate), but `proxyExternalRequest` (in `config-matchers.ts`) and `__proxyExternalRequest` (inlined in `app-dev-server.ts`) forward the upstream `content-encoding` and `content-length` headers as-is to the browser. The browser sees `content-encoding: gzip` and attempts to decompress the body again, but it has already been decompressed by Node — resulting in `ERR_CONTENT_DECODING_FAILED`. ## Reproduction ```ts // next.config.ts const nextConfig: NextConfig = { rewrites: () => [ { source: "/api/:path*", destination: `${process.env.BACKEND_URL}/api/:path*`, }, ], }; ``` Any request to `/api/...` that returns a gzip-compressed response from the backend will fail in the browser. ## Expected Behavior The proxy should strip `content-encoding` and `content-length` from the upstream response headers before forwarding to the browser, since Node `fetch()` has already decompressed the body. ## Suggested Fix In both `proxyExternalRequest` (`config-matchers.ts`) and `__proxyExternalRequest` (`app-dev-server.ts`), filter out `content-encoding` and `content-length` when building response headers: ```ts upstreamResponse.headers.forEach((value, key) => { const lk = key.toLowerCase(); if (!HOP_BY_HOP_HEADERS.has(lk) && lk !== "content-encoding" && lk !== "content-length") { responseHeaders.append(key, value); } }); ``` ## Environment - vinext: 0.0.21 - Node.js: v22 - Browser: Chrome
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#67
No description provided.