Skip to content

[finding] When getAvailablePort exhausts its 100-port search, os serve silently retries the port it already knows is busy and dies on a raw kernel error #12620

Description

@os-litant

Filed unassigned and ungraded by the #12543 dev, session session_01UjujZN219uFzBhSYfMykCd, while implementing that card's drift notice. ⛔ Not graded, not routed. Out of scope for #12543 and deliberately not folded into its PR — repairing it would change what os servedoes, which #12543's rulings forbid.

Measured

packages/cli/src/commands/serve.ts, in the development auto-shift branch guarded by the line reading const portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development';:

try{port=awaitgetAvailablePort(requestedPort);}catch{// Ignore — fall through and try the requested port.}

and the helper it calls, whose comment reads Helper to find available port (dev convenience — see the gated caller):

while(!(awaitisPortAvailable(port))){port++;if(port>startPort+100){thrownewError(`Could not find an available port starting from ${startPort}`);}}

So when 101 consecutive ports are busy, getAvailablePort throws a message that names the problem exactly — and the caller discards it. Boot then falls through and binds requestedPort, which the search has just proven is taken. The result is a boot that dies on the kernel's raw EADDRINUSE, with:

⚠️ So this is the one shape in the whole port policy where the operator gets neither half of the legibility work the family has been landing. The two halves are each correct, and the gap is exactly between them.

Why the catch is not obviously wrong

The fallthrough is defensible on its own terms: a dev whose next 100 ports are all busy arguably wants the requested port attempted rather than a hard refusal. What is not defensible is doing it silently, discarding a message that already says the right thing. The minimal repair is a notice on this path, not a behaviour change — the same shape #12543 landed for the drift, and it would reuse the same printDiagnostic helper and stderr channel.

Not established here

Re-check

git grep -n "Could not find an available port" origin/main -- packages/cli/src/commands/serve.ts
git grep -n "Ignore — fall through and try the requested port" origin/main -- packages/cli/src/commands/serve.ts

Dedup

Searched open + closed issues for the exhausted-search path: #12543 (the drift notice — a different branch of the same if), #12525 / #12526 / #12548 / #12441 (all consumer-side, all closed), #11113 (the production no-auto-select rule — a different branch again), #10167 (a TOCTOU probe in sdui_pick_free_port, different subsystem). None covers the exhausted-search fallthrough.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions