Skip to content

WASI runner crashes streaming large test reports (child exits 1; missing report:end marker) #10

Description

@JairusSW

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=0all 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

  1. 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).
  2. ast test on Node 24 → passes.
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions