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.
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 whatos servedoes, which #12543's rulings forbid.Measured
packages/cli/src/commands/serve.ts, in the development auto-shift branch guarded by the line readingconst portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development';:and the helper it calls, whose comment reads
Helper to find available port (dev convenience — see the gated caller):So when 101 consecutive ports are busy,
getAvailablePortthrows a message that names the problem exactly — and the caller discards it. Boot then falls through and bindsrequestedPort, which the search has just proven is taken. The result is a boot that dies on the kernel's rawEADDRINUSE, with:Port <n> is already in useline — that text lives only in the production branch (theelse if), which this boot never enters,getAvailablePortreturns a DIFFERENT port than requested and nothing says so — the drift is announced nowhere, and three test files have been silently talking past it #12543 either: that one is guarded onport !== requestedPort, and on this path they are equal.Why the
catchis not obviously wrongThe 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
printDiagnostichelper and stderr channel.Not established here
NODE_ENV !== 'production'still open in a real production deployment that never sets NODE_ENV (os servedoes not force it,os startdoes) #11113's policy split).Re-check
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 insdui_pick_free_port, different subsystem). None covers the exhausted-search fallthrough.