Repository navigation
fix(runtime): reject zero-progress JS stream writes - #1747
Merged
Lorenzobattistela merged 1 commit intoOct 19, 2026
Merged
Conversation
Lorenzobattistela
approved these changes
Oct 19, 2026
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.
Problem and fix
The JS runtime's standard-stream writer retries without advancing when
fs.writeSyncreturns zero for nonempty data; repeated zero returns make it spin indefinitely. Reject that result through its existing short-write failure path (exit 1), using the same small guard as the CLI writer in #1691. This extends the zero-progress rule already applied to File.write in #1446.Blast radius
Five replacement lines in
bend2/comp.ts's JSio_out, used by stdout/stderr effects and emitted result output, plustests/io/stream_write_zero.{bend,js}. Successful writes, positive short writes, EINTR/EAGAIN retries and EPIPE→SIGPIPE behavior retain their existing paths. A nonempty zero-byte host return now fails immediately instead of retrying. Native C and the separate CLI writer are unchanged.Regression evidence
The JS-only fixture serializes the runtime's actual
io_outinto bounded children and injects zero returns for stdout and stderr. Source execution and emitted Bun/Node print1on mainf5cee564(fails expected0) and0with the fix. Each child has a two-second deadline; the broken fixture stops after its first failed child.Checks
comp.tsis 65,541/66,000 tokens.git diff --checkand GitHub’srepo-gatecheck pass.--checkupimports and emitted Bun/Node. Eight fixtures, including the new regression, pass their applicable local lanes (30 checks).Validation limits
Zero returns are deliberately injected; no ordinary OS occurrence or prevalence is established. Checked locally on macOS arm64, Bun 1.3.11 and Node 26.8.2. Full cluster tests, Linux runtime tests and GPU checks were not run; GitHub CI ran the repository gate on Linux. The existing file-write and EPIPE foreign fixtures require Bun FFI, so their Node lanes were skipped; separate Node controls cover the changed writer and real EPIPE. C text comparison is limited to two samples; native binaries and a full TypeScript check were not run.