Skip to content

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

Description

@antoinerousseau

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.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions