ITADN

experimental.testProxy hangs raw TCP sockets (regression in 16.3.0, works in 16.2.12)

#96768Openantoinerousseau 创建于 17 天前
A
antoinerousseaucommented
### Link to the code that reproduces this issue https://github.com/antoinerousseau/next-testproxy-repro ### To Reproduce ```bash 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: ```js 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: ```js 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.)
2 条评论