fix(test): base the dev-server test ports past the fetch bad-ports list - #1461
Merged
Conversation
test/bun/dev-public-before-warm.mjs failed CI on #1460 with a bare [TypeError: fetch failed] whose cause was "bad port", naming nothing in the code under test. The port is derived as base + (process.pid % n), and the range was 10000-10255. 10080 is the last entry on the WHATWG Fetch bad-ports list, so fetch() rejects it before opening a socket and no server is involved in the failure at all. A run whose pid was 80 mod 256 therefore failed every request in the file. That is about one run in 256, and it is deterministic given the pid rather than timing-dependent, which is exactly what makes it read as flake and survive a re-run. dev-morph-verdict.mjs had the same exposure on 9990-10229 and had simply not been unlucky yet. Both are now based past 10080: 10100-10355 and 10400-10639. Scanning 9400-10700 confirms 10080 is the only blocked port in the neighbourhood, so any base above it is permanently safe. The ranges stay disjoint from each other and remain entirely above the 9989 ceiling that the existing comment in dev-public-before-warm reasons about, so its collision argument is preserved. That comment was not wrong, it just predated the blocklist constraint, and it now records both.
vivek7405
added a commit
that referenced
this pull request
Sep 2, 2026
#1461 re-based two dev-server test ports off 10080, which fixed those two files and nothing else. The next dev-server test starts from a copy of whichever neighbour is nearest, so the same range can come back. The bug is worth guarding as a CLASS rather than as two constants, because its cost is out of proportion to the typo. It is deterministic given the pid rather than timing-dependent, so a re-run goes green and it reads as flake for as long as it survives. And the symptom points nowhere near the cause: dev-morph-verdict fails as "dev server never came up" while its own captured log says the server is ready on 10080. The server is fine, the poll just cannot reach it. This reads the port declarations out of the source and fails if any range covers a WHATWG bad port. It reads rather than imports because these modules spawn a real dev server on import, so evaluating them here would cost minutes and, at the wrong pid, would be the very failure being guarded against. The second assertion is the one that matters most: it fails if the guard stops finding the declarations at all. Without it the first passes vacuously the moment the idiom is respelled, which is the same shape as the og-card fit pass that shipped with a condition that could never be false. Both assertions were verified against their counterfactuals: the first fails when a port base is reverted, the second when the pattern is broken.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
test/bun/dev-public-before-warm.mjsfailed CI on #1460 with a bare[TypeError: fetch failed]whose cause wasbad port, naming nothing in the code under test. It is not a race and not flake in the usual sense.Cause
The port is derived as
base + (process.pid % n), and the range was10000-10255:10080 is the last entry on the WHATWG Fetch bad-ports list, so
fetch()rejects it before it opens a socket. No server is involved in the failure at all. Reproduced locally:So a run whose pid is
80 mod 256fails every request in the file. That is about one run in 256, and it is deterministic given the pid rather than timing-dependent, which is what makes it read as flake and survive a re-run.dev-morph-verdict.mjshad the same exposure on9990-10229and had simply not been unlucky yet. The other three pid-derived ports sit below 10080 and are safe:dev-reload-retrydev-hot-reloaddev-extra-watchdev-morph-verdictdev-public-before-warmFix
Both are based past 10080:
10100-10355and10400-10639.Scanning 9400-10700 with
fetch()confirms 10080 is the only blocked port in the neighbourhood, so any base above it is permanently safe rather than merely lucky.The new ranges stay disjoint from each other and remain entirely above the 9989 ceiling that the existing comment in
dev-public-before-warm.mjsreasons about, so its collision argument is preserved intact. That comment was not wrong; it reasoned carefully about ranges not colliding with each other and simply predated the blocklist constraint. It now records both, so the next person choosing a port has the whole rule in one place.Verification
Ports and syntax only, no behaviour change to any assertion.
node --checkpasses on both files, and the new ranges are confirmed clear of 10080.