Claude自动发现并报告Bun运行时中child_process.spawn忽略encoding选项导致与Node.js不兼容的bug,robobun自动修复,避免使用execa的库崩溃,展示AI协作开发未来
AI 摘要
Claude自动发现并报告Bun运行时中child_process.spawn忽略encoding选项导致与Node.js不兼容的bug,robobun自动修复,避免使用execa的库崩溃,展示AI协作开发未来。
推荐理由常规快讯,保留列表
原文
Note
AI-generated issue. This bug was found, root-caused, and written up by an AI agent (Claude) while testing OpenClaw against Bun canary, on behalf of and reviewed by @steipete.
What version of Bun is running?
1.4.0-canary.1+43d60f69c (Rust rewrite, current main) — also reproduces on stable 1.3.14 (Zig), so this is a longstanding Node-compat divergence, not a rewrite regression.
What platform is your computer?
Darwin 27.0.0 arm64 (Apple Silicon macOS)
What steps can reproduce the bug?
const { spawn } = require("node:child_process");
const child = spawn("echo", ["hi"], { encoding: "buffer" });
child.stdout.on("data", (d) => console.log("data", d));
child.on("exit", (code) => console.log("exit", code));Run with bun repro.cjs.
What is the expected behavior?
Node's child_process.spawn does not have an encoding option and ignores unknown option keys:
$ node repro.cjs
data <Buffer 68 69 0a>
exit 0This matters in practice because execa passes its entire normalized options object to child_process.spawn, and encoding: "buffer" is a documented, first-class execa option (execa's getSpawnOptions in lib/terminate/kill-descendants.js spreads the user options straight into the spawn call). Any execa caller using encoding: "buffer" therefore crashes on Bun. We hit this in OpenClaw, where every child process goes through execa with encoding: "buffer"; under Bun each spawn dies with this error.
What do you see instead?
TypeError: Unknown encoding: buffer
code: "ERR_UNKNOWN_ENCODING"
at new ReadableState (internal:streams/readable:46:20)
at new Readable (internal:streams/readable:150:28)
at constructNativeReadable (internal:streams/native-readable:5:61)
at #getBunSpawnIo (node:child_process:611:129)
at get (node:child_process:847:59)
at #createStdioObject (node:child_process:660:27)
at get (node:child_process:873:68)Additional information
Root cause (from current main, src/js/node/child_process.ts):
ChildProcessstores the spawn option:this.#encoding = options.encoding || undefined;(line ~1385)- The stdio getters call
#getBunSpawnIo(i, this.#encoding, ...), which builds the stdout/stderr streams viarequire("internal/streams/native-readable").constructNativeReadable(value, { encoding })(line ~1250) ReadableStatevalidatesencodingwithBuffer.isEncoding;"buffer"is not a real encoding, so it throwsERR_UNKNOWN_ENCODING.
Note the asymmetry inside Bun itself: the spawnSync path already special-cases "buffer" (if (outputStdout && encoding && encoding !== "buffer"), line ~602), so spawnSync(..., { encoding: "buffer" }) works while spawn throws.
Two possible fixes, in order of Node fidelity:
- Match Node exactly:
spawnignoresoptions.encodingentirely (Node'sChildProcessnever reads it; onlyexec/execFileconsume it, and they apply it after spawning). - Minimal: treat
"buffer"(and non-Buffer.isEncodingvalues) as "no encoding" when constructing the spawn stdio streams, mirroring the existingspawnSynchandling.
Either unbreaks execa's encoding: "buffer" users.
讨论
暂无评论。