---
date: 2026-05-10
topic: Claude Agent SDK 在 Linux glibc 系统上误选 musl 二进制导致 "native binary not found"
context: packages/agent-client/service 跑 SDK CLI smoke test 时翻车
package: "@anthropic-ai/claude-agent-sdk@0.2.138"
---

# 现象

跑 `npx tsx src/cli.ts "..."`，service.ts 调 `query()`，立即抛错：

```
[error] Claude Code native binary not found at
  /path/to/node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl/claude.
Please ensure Claude Code is installed via native installer or specify a valid
path with options.pathToClaudeCodeExecutable.
```

**误导**：错误说 "native binary not found"，但 `ls` 检查那个 musl 路径 binary 是**真存在的**（225 MB）。

# 根因

`@anthropic-ai/claude-agent-sdk@0.2.x` 的依赖树同时拉了：
- `claude-agent-sdk-linux-x64`（glibc 版）
- `claude-agent-sdk-linux-x64-musl`（musl 版）

SDK 内部的 platform 选择逻辑在某些 glibc 系统上会**优先**挑 musl 变体。但 musl 二进制的动态加载器是 `/lib/ld-musl-x86_64.so.1`，glibc 系统上不存在，内核 `execve()` 失败返回 ENOENT —— SDK 抓到 ENOENT 报成"binary not found"，掩盖了真正的 libc 不匹配问题。

验证方法：

```bash
# glibc 版（OK）
node_modules/@anthropic-ai/claude-agent-sdk-linux-x64/claude --version
# → 2.1.138 (Claude Code)  ✓

# musl 版（ENOENT 但 binary 在那里）
node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl/claude --version
# → /bin/bash: cannot execute: required file not found
```

# 修法：通过 `pathToClaudeCodeExecutable` 选项强制选对的二进制

`query()` 的 `Options` 暴露 `pathToClaudeCodeExecutable?: string`。我们写一个跨平台 resolver
显式给它赋值。

```ts
import { createRequire } from "node:module";
import { existsSync } from "node:fs";
import path from "node:path";

const requireFn = createRequire(import.meta.url);

function resolveClaudeBinary(): string | undefined {
  // 1. 显式 env 覆盖
  if (process.env.CLAUDE_CODE_EXECUTABLE && existsSync(process.env.CLAUDE_CODE_EXECUTABLE)) {
    return process.env.CLAUDE_CODE_EXECUTABLE;
  }

  // 2. 顺着 SDK 的安装位置找平台 sibling 包
  let sdkDir: string;
  try {
    sdkDir = path.dirname(requireFn.resolve("@anthropic-ai/claude-agent-sdk"));
  } catch {
    return undefined;
  }
  const parent = path.dirname(sdkDir); // node_modules/@anthropic-ai

  // 3. 平台候选列表，glibc 优先于 musl
  const candidates: string[] = [];
  if (process.platform === "linux" && process.arch === "x64") {
    candidates.push(
      path.join(parent, "claude-agent-sdk-linux-x64", "claude"),       // glibc
      path.join(parent, "claude-agent-sdk-linux-x64-musl", "claude"),  // fallback
    );
  } // ... 其它平台同理

  for (const p of candidates) if (existsSync(p)) return p;
  return undefined;
}

// query options
{
  pathToClaudeCodeExecutable: resolveClaudeBinary(),
  // ...
}
```

# 验证

修完后再跑 CLI：

```
[cli] AGENT_CWD = /.../packages/agent-client
[cli] session = 34a52cee-5141-473a-adbf-1ca2f8d8f024
[tool_use] Bash({"command":"ls -la ..."})
[tool_result] OK: ...
[done] cost=$0.1651 tokens=in:5/out:382
```

完整 agent loop 通了：Bash 工具实际执行，agent 自我纠错（第一次 ls 路径错→第二次 pwd && ls），
流式 markdown 输出，session 留痕。

# 适用范围 / 防御

1. **任何 Linux 服务器/容器跑 Claude Agent SDK 都要警惕**——尤其是 glibc 系（Ubuntu / Debian /
   RHEL / Amazon Linux），SDK 默认行为可能 broken
2. Alpine 容器（musl 默认）应该没事，但**不要混跑**（glibc node 装的 SDK 拷到 Alpine 反过来也错）
3. 如果是用 ncc bundle 打包成 sidecar 给 Tauri 用，**必须在目标平台上 bundle**——Linux x64 glibc 上
   bundle 出来的，拷到 Mac / Alpine 都跑不了
4. 看到 SDK 报 "native binary not found at <存在的路径>"，先用 `file` / `ldd` 看二进制的 ABI 跟系
   统是否匹配，再考虑 path 是否真错
5. 该 resolver 直接复用到任何想用 `claude-agent-sdk` 的项目；建议封装成共享工具
