Repository navigation
fix(devframe): skip ports held on another loopback address - #461
Conversation
|
@DBAAZzz is attempting to deploy a commit to the NuxtLabs Team on Vercel. A member of the Team first needs to authorize it. |
|
👁️🗨️ Review this pull request with grouped, summarized diffs at: raw result💭 analyzed by {
"headSha": "873529d6386c66e50d5e76494313900dc7f9b440",
"result": {
"overallSummary": "Fixes an issue where devframe's dev server could silently share a port with another process already listening on `127.0.0.1`, because `get-port-please` only probed one loopback address. The fix centralizes \"bind on a host plus its loopback twin\" logic in a new `node/listen.ts` module, wires it into `createDevServer` with a retry-on-taken-port loop (while still failing fast for an explicitly pinned port), and adds tests that reproduce and verify the fix.",
"groups": [
{
"key": "loopback-port-fix",
"label": "Loopback port binding fix",
"summary": "Fixes a dev server port collision bug: when another process already holds `127.0.0.1:<port>`, the previous port resolution (via `get-port-please`) still reported the port as free for `localhost`, causing devframe to bind only `[::1]:<port>` while requests on `127.0.0.1` silently reached the other process. The loopback-twin bind/retry logic is extracted from `instance-shell.ts` into a shared `node/listen.ts` helper and reused by `createDevServer`, which now retries with a new port when the requested one (or its loopback twin) is actually taken, while a pinned `--port` still fails fast with `DF0052`. `cac.ts` is updated to pass the preferred port through as `defaultPort` instead of pre-resolving it.",
"category": "core",
"filePaths": [
"packages/devframe/src/adapters/dev.ts",
"packages/devframe/src/node/listen.ts",
"packages/devframe/src/node/instance-shell.ts",
"packages/devframe/src/adapters/cac.ts"
],
"critical": true,
"fileNotes": [
{
"path": "packages/devframe/src/node/listen.ts",
"text": "New shared helper extracted from instance-shell.ts; binds the requested host and, for localhost, also binds the other loopback address, failing like a taken port if that twin bind is refused."
},
{
"path": "packages/devframe/src/adapters/dev.ts",
"text": "createDevServer now retries port resolution up to 3 times on EADDRINUSE/EACCES when the port wasn't explicitly pinned, using the new listenWithLoopbackTwin helper."
}
]
},
{
"key": "tests",
"label": "Tests and snapshot",
"summary": "Adds regression tests that reproduce the loopback port-sharing bug (one holding 127.0.0.1 before starting the dev server) and verify both that an unpinned port moves off the taken one and that a pinned port fails with DF0052; the type snapshot is updated for the new `defaultPort` option.",
"category": "tests",
"filePaths": [
"packages/devframe/src/adapters/__tests__/dev.test.ts",
"tests/__snapshots__/tsnapi/devframe/adapters/dev.snapshot.d.ts"
],
"critical": true
}
],
"schemaVersion": 1,
"source": "llm",
"generatedAt": "2026-10-30T21:35:09.795Z",
"model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
"locale": "en"
}
} |
…loopback-families # Conflicts: # pnpm-lock.yaml
Drop the `get-port-please` patch. `createDevServer` on `localhost` now also listens on the other loopback address, like the side-car does since `EADDRINUSE` and a port that was not pinned moves to the next free one. A pinned `port` / `--port` still fails with `DF0052`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I pushed two commits to this branch. The fix now works without patching Why #462 did not fix this: #462 made the side-car listen on both loopback addresses. What changed
Why not the patch: the bind itself checks the port, so there is no race between a probe and the bind. Pages on Not covered: wildcard hosts like CI: lint, typecheck and the devframe tests (706 of 706) pass. CI on |
fix #460
If another server holds
127.0.0.1:<port>,getPortfromget-port-pleasestill returns that port forlocalhost, because it tries to bind only one address. devframe then binds[::1]:<port>, and requests to127.0.0.1:<port>go to the other server.This PR patches
get-port-please. devframe bundles it, so the patch ships with devframe. For a loopback or wildcard host,getPortnow also tries127.0.0.1,::1,0.0.0.0and::. If one of them fails withEADDRINUSEorEACCES, the port is in use. Other errors, likeEADDRNOTAVAILwhen IPv6 is off, mean that the address does not exist, so they are ignored.The new test in
dev.test.tsfails onmainand passes with the patch, on Linux (IPv6 on) and on macOS. I will send the same change upstream for unjs/get-port-please#121. You can remove the patch after upstream releases it.