# Claude自动发现并报告Bun运行时中child_process.spawn忽略encoding选项导致与Node.js不兼容的bug，robobun自动修复，避免使用execa的库崩溃，展示AI协作开发未来

- 来源：Peter Steinberger
- 发布时间：2026-07-27 23:45
- AIWatch 分数：59
- AIWatch 标记：当日精选
- AIWatch 链接：https://aiwatch.icu/events/evt_01kyj5f44wssyrzkw3n81rcfwk
- 原文链接：https://x.com/steipete/status/2081767828278170002

## 精选理由

常规快讯，保留列表

## 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 0

This 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):

ChildProcess stores the spawn option: this.#encoding = options.encoding || undefined; (line ~1385)
The stdio getters call #getBunSpawnIo(i, this.#encoding, ...), which builds the stdout/stderr streams via require("internal/streams/native-readable").constructNativeReadable(value, { encoding }) (line ~1250)
ReadableState validates encoding with Buffer.isEncoding; "buffer" is not a real encoding, so it throws ERR_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: spawn ignores options.encoding entirely (Node's ChildProcess never reads it; only exec/execFile consume it, and they apply it after spawning).
Minimal: treat "buffer" (and non-Buffer.isEncoding values) as "no encoding" when constructing the spawn stdio streams, mirroring the existing spawnSync handling.

Either unbreaks execa's encoding: "buffer" users.
