Summary
The release PR #395 (v0.3.0) is currently blocked because CI is failing on Node.js 22 (ubuntu-latest). This issue tracks the root cause, the current fix, and open questions about long-term correctness.
Background
PR #410 upgraded commander v14 → v15. Commander 15 is ESM-only, which introduced a subtle Linux-specific failure in the test suite on Node.js 22.22.x.
What's failing
In test/factory.test.ts, the invokeWithJsonFormat helper function patches process.stderr.write globally to capture output. On Linux Node 22.22.x (but not macOS, and not Node 24/25), something in the tsx/esm + Node internals writes to process.stderr.write between tests in the schema input - JSON format error output suite, contaminating the captured out buffer with non-JSON content. When JSON.parse(out) is called afterwards, it fails silently and parsed comes back null, causing:
TypeError: Cannot read properties of null (reading 'error')
at factory.test.ts:1758
Only the second test in the suite fails consistently — the first test runs clean but leaves behind something that poisons the global stderr write handle for the next test.
Two-part change:
-
src/factory.ts — the JSON-format input validation error was written directly to process.stderr.write(json). Changed to route through cmd.configureOutput().writeErr(json) instead, which respects commander's own output configuration layer (the same channel the test helper already captures via cmd.configureOutput({ writeErr })).
-
test/factory.test.ts — removed the global process.stdout/stderr.write patching from invokeWithJsonFormat entirely. The helper now relies solely on configureOutput captures, which are per-invocation and don't touch global state.
The fix passes locally on Node 22.23.0 (macOS) and Node 26 across all 5 tests in the suite.
Uncertainty — is this the right long-term fix?
I am not fully confident this is the correct long-term approach. A few open questions:
1. Other direct stream writes in factory.ts
There are roughly 10 other process.stdout.write / process.stderr.write calls in factory.ts inside action handlers (lines ~516, 589, 591, 601, 603, 615, 619, 623, 631, 633, 635). PR #444 only fixes the one failing line (574). The others aren't currently failing — but they carry the same structural risk on Node.js 22. Should a follow-up PR migrate all of them to route through cmd.configureOutput()?
2. Root cause is still somewhat unclear
I cannot fully explain why Linux Node 22.22.3 behaves differently from macOS Node 22.23.0. Node 22.23.0 is a security-only release with no test runner changes. The failure may be an environment artifact specific to the ubuntu-latest runner image rather than a real Node.js version difference. If so, the test change (removing global patches) is the more important fix, and the factory change may be incidental.
3. process.stderr.write patching pattern elsewhere
Several other test helpers in factory.test.ts also patch process.stdout/stderr.write globally (lines ~1865, 2014, 3739, 3761). If the root cause is a platform-specific interaction with the tsx/esm loader, those helpers could exhibit similar issues in the future.
Summary
The release PR #395 (v0.3.0) is currently blocked because CI is failing on Node.js 22 (ubuntu-latest). This issue tracks the root cause, the current fix, and open questions about long-term correctness.
Background
PR #410 upgraded commander v14 → v15. Commander 15 is ESM-only, which introduced a subtle Linux-specific failure in the test suite on Node.js 22.22.x.
What's failing
In
test/factory.test.ts, theinvokeWithJsonFormathelper function patchesprocess.stderr.writeglobally to capture output. On Linux Node 22.22.x (but not macOS, and not Node 24/25), something in the tsx/esm + Node internals writes toprocess.stderr.writebetween tests in theschema input - JSON format error outputsuite, contaminating the capturedoutbuffer with non-JSON content. WhenJSON.parse(out)is called afterwards, it fails silently andparsedcomes backnull, causing:Only the second test in the suite fails consistently — the first test runs clean but leaves behind something that poisons the global stderr write handle for the next test.
Current fix — PR #444
Two-part change:
src/factory.ts— the JSON-format input validation error was written directly toprocess.stderr.write(json). Changed to route throughcmd.configureOutput().writeErr(json)instead, which respects commander's own output configuration layer (the same channel the test helper already captures viacmd.configureOutput({ writeErr })).test/factory.test.ts— removed the globalprocess.stdout/stderr.writepatching frominvokeWithJsonFormatentirely. The helper now relies solely onconfigureOutputcaptures, which are per-invocation and don't touch global state.The fix passes locally on Node 22.23.0 (macOS) and Node 26 across all 5 tests in the suite.
Uncertainty — is this the right long-term fix?
I am not fully confident this is the correct long-term approach. A few open questions:
1. Other direct stream writes in
factory.tsThere are roughly 10 other
process.stdout.write/process.stderr.writecalls infactory.tsinside action handlers (lines ~516, 589, 591, 601, 603, 615, 619, 623, 631, 633, 635). PR #444 only fixes the one failing line (574). The others aren't currently failing — but they carry the same structural risk on Node.js 22. Should a follow-up PR migrate all of them to route throughcmd.configureOutput()?2. Root cause is still somewhat unclear
I cannot fully explain why Linux Node 22.22.3 behaves differently from macOS Node 22.23.0. Node 22.23.0 is a security-only release with no test runner changes. The failure may be an environment artifact specific to the ubuntu-latest runner image rather than a real Node.js version difference. If so, the test change (removing global patches) is the more important fix, and the factory change may be incidental.
3.
process.stderr.writepatching pattern elsewhereSeveral other test helpers in
factory.test.tsalso patchprocess.stdout/stderr.writeglobally (lines ~1865, 2014, 3739, 3761). If the root cause is a platform-specific interaction with the tsx/esm loader, those helpers could exhibit similar issues in the future.