Summary
The WASI runner crashes when a spec produces a large test report. The tests themselves run and pass, but the run fails while the report is streamed back from the runner child to the parent — the child exits with code 1 mid-stream and the parent reports missing report:end marker for chunked report payload.
It reproduces in CI but not locally, and the only difference is the host Node version, so it looks like large report writes over the runner↔parent pipe aren't robust to a slow/backpressured/partial-write consumer on some Node versions.
Environment
- as-test
1.6.0
- assemblyscript
0.28.18, @assemblyscript/wasi-shim 0.1.0
- target:
wasi (default node ./.as-test/runners/default.wasi.js <file> runner)
- Fails: GitHub Actions
ubuntu-latest (preinstalled Node)
- Passes: local Node
v24.16.0
- Spec size: two auto-generated specs with ~20k
expect().toBe() assertions each → a ~1.35 MB chunked report (21 chunks)
Symptom (CI output)
FAIL dtoa.spec.ts 0.0ms (failed: swar, simd)
Oops! Looks like the runtime crashed!
child process exited with code 1
runtime diagnostics: exitCode=1, channelClose=no
report stream: dataFrames=0, dataBytes=0, chunked=no, chunkStart=no, chunkEnd=no, ...
runtime events: fileStart=yes, fileEnd=yes, fileVerdict=ok, suiteStarts=3, suiteEnds=3, assertionFails=0, warnings=0, logs=0
and for the other spec:
could not parse report payload: missing report:end marker for chunked report payload
runtime diagnostics: exitCode=1, channelClose=no
report stream: dataFrames=0, dataBytes=0, chunked=yes, chunkStart=yes, chunkEnd=no,
chunkFrames=0, expectedChunkFrames=21, chunkBytes=0, expectedChunkBytes=1350857
runtime events: fileStart=yes, fileEnd=yes, fileVerdict=ok, suiteStarts=2, suiteEnds=2, assertionFails=0
The key tell: suiteStarts == suiteEnds and assertionFails=0 — all suites ran to completion with no failures. The crash is purely in delivering the report:
- one spec announced a 21-chunk / 1,350,857-byte report (
chunkStart=yes, expectedChunkFrames=21) but sent 0 of them (chunkFrames=0, chunkEnd=no) before the child exited 1;
- the other emitted no frames at all (
dataFrames=0) before exiting 1.
Reproduction
- Generate/author a spec with a very large number of assertions so the report is > ~1 MB (a few thousand
expect().toBe() with non-trivial string values does it).
ast test on Node 24 → passes.
ast test on an older Node (e.g. the ubuntu-latest default) → both large specs crash as above; a small spec in the same run (misc.spec.ts) passes.
Suggested fix
The report path should stream defensively for large payloads:
- Chunk the report into bounded frames (e.g. ≤ 64 KB) and write them with backpressure handling — respect
process.stdout.write()'s false return / 'drain', or loop on fs.writeSync handling partial writes + EAGAIN on the runner side, and make sure the parent's reader reassembles streamed chunks without assuming a single write.
- Ensure the runner flushes and waits for the report to drain before
proc_exit/process exit, so the child can't exit 1 with frames still buffered.
- Optionally, for payloads above a threshold, hand the report off via a temp file instead of the stdout pipe, sidestepping pipe-buffer/partial-write differences across Node versions entirely.
Happy to provide a minimal repro repo if useful — the project that hit this is a dtoa/ftoa library whose generated golden-value specs are intentionally huge.
Summary
The WASI runner crashes when a spec produces a large test report. The tests themselves run and pass, but the run fails while the report is streamed back from the runner child to the parent — the child exits with code 1 mid-stream and the parent reports
missing report:end marker for chunked report payload.It reproduces in CI but not locally, and the only difference is the host Node version, so it looks like large report writes over the runner↔parent pipe aren't robust to a slow/backpressured/partial-write consumer on some Node versions.
Environment
1.6.00.28.18,@assemblyscript/wasi-shim0.1.0wasi(defaultnode ./.as-test/runners/default.wasi.js <file>runner)ubuntu-latest(preinstalled Node)v24.16.0expect().toBe()assertions each → a ~1.35 MB chunked report (21 chunks)Symptom (CI output)
and for the other spec:
The key tell:
suiteStarts == suiteEndsandassertionFails=0— all suites ran to completion with no failures. The crash is purely in delivering the report:chunkStart=yes,expectedChunkFrames=21) but sent 0 of them (chunkFrames=0,chunkEnd=no) before the child exited 1;dataFrames=0) before exiting 1.Reproduction
expect().toBe()with non-trivial string values does it).ast teston Node 24 → passes.ast teston an older Node (e.g. theubuntu-latestdefault) → both large specs crash as above; a small spec in the same run (misc.spec.ts) passes.Suggested fix
The report path should stream defensively for large payloads:
process.stdout.write()'sfalsereturn /'drain', or loop onfs.writeSynchandling partial writes +EAGAINon the runner side, and make sure the parent's reader reassembles streamed chunks without assuming a single write.proc_exit/process exit, so the child can't exit 1 with frames still buffered.Happy to provide a minimal repro repo if useful — the project that hit this is a dtoa/ftoa library whose generated golden-value specs are intentionally huge.