Link to the code that reproduces this issue
https://github.com/antoinerousseau/next-testproxy-repro
To Reproduce
git clone <gist above into a folder> repro && cd repro
pnpm install
node echo-server.js & # plain TCP echo server on :3901
ENABLE_TEST_PROXY=true pnpm build
ENABLE_TEST_PROXY=true ECHO_PORT=3901 pnpm start # next start -p 3900
curl http://localhost:3900/api/probe # hangs forever
The route (app/api/probe/route.js) does nothing but open a raw
net.Socket (no fetch, no HTTP) to a plain TCP echo server, write a byte,
and await the echo:
import net from "node:net";
function probeRawSocket(port) {
return new Promise((resolve, reject) => {
const socket = net.createConnection({ host: "127.0.0.1", port }, () => {
socket.write("ping");
});
socket.on("data", (data) => {
socket.end();
resolve(data.toString());
});
socket.on("error", reject);
});
}
export async function GET() {
const start = Date.now();
const reply = await probeRawSocket(Number(process.env.ECHO_PORT));
return Response.json({ reply, ms: Date.now() - start });
}
next.config.js only sets:
module.exports = {
experimental: {
testProxy: process.env.ENABLE_TEST_PROXY === "true",
},
};
Current vs. Expected behavior
With experimental.testProxy: true on Next.js 16.3.0, the request to
/api/probe never resolves — no response, no error, no timeout. Confirmed
via lsof on the next-server process that the outbound TCP connection to
the echo server is never even opened at the socket level.
With the exact same code and env, only changing the version:
| next version |
testProxy |
result |
| 16.2.12 |
true |
resolves in ~6ms |
| 16.3.0 |
true |
hangs forever |
| 16.3.0 |
false |
resolves in ~3ms |
Expected: testProxy should only intercept fetch()/HTTP traffic (per its
documented purpose for next/experimental/testmode), and should not affect
unrelated raw net.Socket connections — matching the 16.2.12 behavior.
Real-world impact
We hit this via next/experimental/testmode/playwright/msw, which flips this
same flag on to let Playwright/MSW intercept fetch() calls in e2e tests.
One of our API routes also runs a normal pg (node-postgres) query in the
same request. After upgrading 16.2.12 → 16.3.0, every Playwright test whose
setup hits that route now hangs until Playwright's default 30s hook timeout,
and with retries + a single CI worker this silently burns ~90 minutes before
the job reports failure — with no actual error surfaced anywhere. We
confirmed with pg_stat_activity/lsof that Postgres never receives a
connection attempt while stuck.
This minimal repro shows it's not pg-specific — any raw socket traffic
appears to be swallowed by testProxy in 16.3.0 rather than passed through.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.5.0
Node: v24.18.0
Next.js: 16.3.0 (regression; 16.2.12 unaffected)
Also reproduced in CI on ubuntu-24.04 (GitHub Actions), same result.
Which area(s) are affected?
Not sure / Other (experimental.testProxy / next/experimental/testmode)
Additional context
This was discovered while upgrading an app from 16.2.12 to 16.3.0. Reverting
only the next/@next/env version (keeping experimental.testProxy: true)
resolves it, confirming it's a version regression and not a config issue on
our side.
(Previously filed as #96766, auto-closed for linking a gist instead of a repo — refiling with a proper public repo link. Also likely related to #96521, which pins the root cause more precisely: the @mswjs/interceptors bump to socket-level interception in #96059.)
Link to the code that reproduces this issue
https://github.com/antoinerousseau/next-testproxy-repro
To Reproduce
The route (
app/api/probe/route.js) does nothing but open a rawnet.Socket(nofetch, no HTTP) to a plain TCP echo server, write a byte,and await the echo:
next.config.jsonly sets:Current vs. Expected behavior
With
experimental.testProxy: trueon Next.js 16.3.0, the request to/api/probenever resolves — no response, no error, no timeout. Confirmedvia
lsofon thenext-serverprocess that the outbound TCP connection tothe echo server is never even opened at the socket level.
With the exact same code and env, only changing the version:
Expected:
testProxyshould only interceptfetch()/HTTP traffic (per itsdocumented purpose for
next/experimental/testmode), and should not affectunrelated raw
net.Socketconnections — matching the 16.2.12 behavior.Real-world impact
We hit this via
next/experimental/testmode/playwright/msw, which flips thissame flag on to let Playwright/MSW intercept
fetch()calls in e2e tests.One of our API routes also runs a normal
pg(node-postgres) query in thesame request. After upgrading 16.2.12 → 16.3.0, every Playwright test whose
setup hits that route now hangs until Playwright's default 30s hook timeout,
and with retries + a single CI worker this silently burns ~90 minutes before
the job reports failure — with no actual error surfaced anywhere. We
confirmed with
pg_stat_activity/lsofthat Postgres never receives aconnection attempt while stuck.
This minimal repro shows it's not
pg-specific — any raw socket trafficappears to be swallowed by
testProxyin 16.3.0 rather than passed through.Provide environment information
Also reproduced in CI on
ubuntu-24.04(GitHub Actions), same result.Which area(s) are affected?
Not sure / Other (experimental.testProxy / next/experimental/testmode)
Additional context
This was discovered while upgrading an app from 16.2.12 to 16.3.0. Reverting
only the
next/@next/envversion (keepingexperimental.testProxy: true)resolves it, confirming it's a version regression and not a config issue on
our side.
(Previously filed as #96766, auto-closed for linking a gist instead of a repo — refiling with a proper public repo link. Also likely related to #96521, which pins the root cause more precisely: the
@mswjs/interceptorsbump to socket-level interception in #96059.)