Skip to content

fix(fs): match Node read and write argument defaults - #80

Merged
steipete merged 2 commits into
mainfrom
claude/fs-read-undefined-w93
Oct 2, 2026
Merged

steipete merged 2 commits into
mainfrom
claude/fs-read-undefined-w93

Conversation

@steipete

@steipete steipete commented Oct 2, 2026 •

Copy link
Copy Markdown

fs.readSync(fd, buffer, undefined, undefined, undefined) threw an ERR_OUT_OF_RANGE NaN-length error. Node coerces that positional length to zero. Bun also stopped parsing buffer writes at an undefined offset, silently ignoring later length and position arguments.

Normalize the public overloads before native I/O. Synchronous/callback reads retain Node's signed 32-bit length coercion; FileHandle.read retains its distinct nullish-length default. Validate positions even for zero-byte reads and preserve exact range/type errors and their delivery order. Writes consume each argument independently and preserve the string overload's UTF-8 fallback. Native backing-store and bounds checks remain in place. The existing expected-failure test for explicit undefined lengths is now enabled.

Upstream research found oven-sh/bun#37647, whose write-slot/default behavior is adapted here in the JavaScript normalization layer. Thanks @robobun! Closed #29017 covers only part of zero-length position validation; no complete read-default fix was found. The complete change is proposed upstream in oven-sh/bun#44476, with an upstream-base Darwin build and oracle proof.

Validation: Node 24.21.0 oracle covering 1,227 argument shapes; every one of the 1,217 non-crashing Node outcomes matches exactly, including codes, messages, byte counts, written bytes and callback/rejection channels. Ten malformed FileHandle length inputs abort Node itself; Bun retains recoverable behavior. Regression groups fail on fork 13311cf83e. All 25 filesystem test files pass through the repository's official runner. All 20 selected ported Node read/write tests pass under Node 24 and patched Bun after restoring the empty-buffer test's exact Node diagnostics. Scoped P2 review, lint, built-in TypeScript checking and formatting pass.

OpenClaw consumer comparison is pinned to 8d756e9c009b2: Node passes 271 wrapper tests; 13311cf83e passes 269 and fails the capsule readSync case plus an independent retained-allocation receipt race. Patched Bun passes 270 wrapper tests and retains only the independent receipt race; the readSync failure is gone. An earlier loaded-run pnpm startup timeout passed on the exact-runtime replay. All 11 additional consumer files pass on Node, baseline Bun and patched Bun (216 tests on each), covering staging, source capsules, process snapshots, call logs, browser auth, heap snapshots and artifact copying. Both Linux x64 and Darwin arm64 CI passed on final head a88111a1843a26a95f53931459128b556a32571a (run 37077526599). Squash-merged as 8d3a4d8ab287dd7136c79136c5cc29aa2eb95f04; the fetched main tree matches the qualified source tree.

Normalize each overload before native I/O, preserving signed read-length coercion, FileHandle defaults, validation order, bigint positions, and exact diagnostics. Adapts the independent write-argument handling from oven-sh#37647, with credit to robobun. Enable the existing explicit-undefined regression and cover sibling overloads.
@steipete
steipete merged commit 8d3a4d8 into main Oct 2, 2026
7 checks passed
@steipete
steipete deleted the claude/fs-read-undefined-w93 branch October 2, 2026 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant