You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test: run_warm_soak reports a client timeout as an #8163 residual — it counts verifier exits instead of classifying the failure #8286
My bug, in the arm I added in #8215. Filing it before fixing it because it is on main now and #8163 is closed, so the next person whose warm soak trips a timeout will see the words #8163 residual and reasonably conclude it has regressed.
What it does wrong
run_warm_soak in tests/release/packages/next-app-route/fixture.sh treats any non-zero verify.mjs exit as a failure and reports:
FAIL next-app-route — warm soak: N failing pass(es) [...], M host TypeError(s) — #8163 residual
It counts exits; it does not classify them. Two very different things produce a non-zero exit:
The residual — the server returns an empty body. Signature: Unexpected end of JSON input in the verifier, plus TypeError: value is not a function and E180 failed to pipe response in the host log.
A client timeout — UND_ERR_HEADERS_TIMEOUT. The server was merely slow; the host log is clean.
In the saturated regime the second happens on its own (see #8213: one pass ran 644 copying minors against a steady 84, and 8 of its 21 concurrent requests timed out). So the arm manufactures false residual reports precisely where it is most likely to be run.
Observed
In the #8163 close-condition run at 211/300 passes: 8 failing passes, allUND_ERR_HEADERS_TIMEOUT, and across 6,267 copying minors the three residual discriminators were 0 / 0 / 0. The arm would have printed #8163 residual for a run with no residual evidence whatsoever.
It is worth being precise about the direction: this arm was written to stop a green run implying more than it proves, and its actual first failure was the mirror image — a red verdict that isn't true. A gate that cannot be trusted when it goes red is as useless as one that cannot go red at all, and I did not think about that direction when I wrote it.
Fix (mine, in progress)
Classify rather than count:
residual → empty body and a host-side TypeError: value is not a function in the same pass. Fail with #8163 residual.
anything else → report verbatim rather than assuming a cause.
Also worth adding while there: emit the per-pass minor counts, since the run above showed a 7.7× single-pass storm that a total would have hidden entirely.
Do not fix this by widening the grep. The lesson is that the arm asserted a cause from an exit code, and the fix is to make it read the evidence it already has in the host log.
A datapoint on how easily this bug hides, from the second host running the same arm.
I ran the same 300-pass native soak on the bench mini, same tree 183d30c53, same instrument, same prebuilt-artifact lineage — 13,089 copying minors, zero UND_ERR_HEADERS_TIMEOUT, so run_warm_soak printed a clean verdict. The other host's run saw 12 timeouts across two collection-storm passes and would have produced the false #8163 residual line this issue describes.
The difference was luck, not configuration: the storms turn out to be stochastic in placement (details in #8213 comment 5314568327 — host A stormed at passes 203 and 238, host B ran more passes and more collections and never stormed). So this defect's visibility is probabilistic in exactly the way that makes it dangerous to leave in place:
it stays invisible across arbitrarily many green runs;
it fires on someone else's machine, at a random point, and points them at a closed issue;
the person who hits it is by construction the person with the least context — they are running the gate, not the investigation that produced it.
Worth noting for whoever reviews #8300: the fix cannot be validated by "run the soak and see no false residual", because a clean run is the expected outcome most of the time. It needs the sabotage direction — inject a timeout, assert the classification says #8213 and not #8163 — which is what #8300 does.
The distinction being fixed here is the load-bearing one for both issues: TypeError: value is not a function + empty body means a GC residual; a client timeout with a clean host log means latency. Counting verifier exits cannot tell those apart, and the two point at completely different bugs.
Activity
fix(test): classify warm-soak failures instead of counting them (#8286)
proggeramlug commentedon Aug 17, 2026
A datapoint on how easily this bug hides, from the second host running the same arm.
I ran the same 300-pass native soak on the bench mini, same tree
183d30c53, same instrument, same prebuilt-artifact lineage — 13,089 copying minors, zeroUND_ERR_HEADERS_TIMEOUT, sorun_warm_soakprinted a clean verdict. The other host's run saw 12 timeouts across two collection-storm passes and would have produced the false#8163 residualline this issue describes.The difference was luck, not configuration: the storms turn out to be stochastic in placement (details in #8213 comment 5314568327 — host A stormed at passes 203 and 238, host B ran more passes and more collections and never stormed). So this defect's visibility is probabilistic in exactly the way that makes it dangerous to leave in place:
Worth noting for whoever reviews #8300: the fix cannot be validated by "run the soak and see no false residual", because a clean run is the expected outcome most of the time. It needs the sabotage direction — inject a timeout, assert the classification says #8213 and not #8163 — which is what #8300 does.
The distinction being fixed here is the load-bearing one for both issues:
TypeError: value is not a function+ empty body means a GC residual; a client timeout with a clean host log means latency. Counting verifier exits cannot tell those apart, and the two point at completely different bugs.fix(test): classify warm-soak failures instead of counting them (Perr…