Status: implemented and verified in 6d797186c on codex/runtime-port; open pending integration into main.
Follow-up to #66 and the fake-clock work in #490.
Root cause and implementation
A native stack sample showed that the unchanged timers-immediate-exception-fixture.js hung during module evaluation, before scheduling its callbacks. Node's common ESM helper eagerly reads common.opensslCli, which calls child_process.spawnSync on an absent absolute executable. Home passed libc posix_spawn's direct positive errno to a -1/errno-style helper, treated ENOENT as success and watched PID 0. A direct missing-absolute-path probe reproduced this; a small handled-immediate ordering probe completed correctly.
Home now preserves posix_spawn's errno and executable path, propagates file-action/attribute setup failures instead of discarding them, and releases the extra-fd registration list on Maybe.err as well as Zig errors. Native object cleanup runs on every return path; successful spawns transfer the list into their owning process. wait4 keeps its separate -1/errno contract. No timer or exception-dispatch implementation was changed.
Verification
HOME_NATIVE_VM=1 HOME_CORPUS_FULL_VM=1 ./zig-out/bin/home-debug run packages/runtime/test/bun-corpus/js/node/timers/timers-immediate-exception-fixture.js
HOME_NATIVE_VM=1 HOME_CORPUS_FULL_VM=1 ./zig-out/bin/home-debug test packages/runtime/test/bun-corpus/js/node/timers/node-timers.test.tsThe unchanged standalone fixture exits successfully, including its real nextTick/microtask order and common.mustCall checks. The full Node timer file passes 20 tests / 31 assertions; before this fix, both the prior Home binary and the fake-clock binary hung after printing 19 passes. Bun's original-checkout control passes 20 / 31 too.
The selected missing-command and Darwin-fd-10240 tests pass 2 tests / 9 assertions (32 filtered cases excluded). The expanded native CLI test repeats absolute missing-path, EACCES and invalid-cwd failures, checks invalid extra-fd setup and descriptor counts, proves valid spawning still works, and verifies that spawnSync does not execute user microtasks. All 21 native regression files pass. Adjacent unchanged checks pass for isolation 19 / 67, core fake timers 30 / 83, timers/promises 4 / 7, and PATH selection 1 / 2. In total, 28 selected commands succeed. Standalone/native commands are not added to upstream test counts.
Native build and cached rebuild: 17/17 steps. Focused Pickier, spawn-wrapper Zig formatting and whitespace checks pass. Eight relevant corpus/helper files were verified byte-for-byte against source pin 4982b91e3702094330f3be3883354c52b8c01323.
Remaining scope
Full child-process: 30 pass / 2 fail / 1 skip / 1 TODO / 70 assertions, with failures tracked as extra stdio #495 and package scripts #497. Full spawnSync: 4 pass / 1 fail / 1 platform skip / 11 assertions, tracked as native counter snapshots #496. Installed Bun 1.3.14 passes those scenarios but fails the newer invalid-fd case itself (full child-process: 31 pass / 1 fail / 1 skip / 1 TODO / 71 assertions). Linux/Windows/PTY coverage, wider native ownership and full-suite parity remain open. No incomplete suite, expected failure, skip or TODO counts as logical completion.