Node + tsx “__name is not a function” 崩溃
概要
通过 Node + tsx 运行 OpenClaw 时,启动阶段就崩溃了:
[openclaw] Failed to start CLI: TypeError: __name is not a function
at createSubsystemLogger (.../src/logging/subsystem.ts:203:25)
at .../src/agents/auth-profiles/constants.ts:25:20
这个问题在开发脚本从 Bun 切换到 tsx 之后开始出现(commit 2871657e,2026-01-06)。同样的运行路径在 Bun 下没问题。
环境
- Node:v25.x(在 v25.3.0 上观察到)
- tsx:4.21.0
- OS:macOS(其他运行 Node 25 的平台也可能复现)
复现步骤(仅 Node)
# 在仓库根目录
node --version
pnpm install
node --import tsx src/entry.ts status
仓库内的最小复现
node --import tsx scripts/repro/tsx-name-repro.ts
Node 版本测试
- Node 25.3.0:失败
- Node 22.22.0(Homebrew
node@22):失败 - Node 24:还没装;待验证
分析和假设
tsx用 esbuild 转换 TS/ESM。esbuild 的keepNames会生成一个__namehelper 并用__name(...)包裹函数定义。- 崩溃信息说
__name存在但不是函数,意味着在 Node 25 的 loader 路径下,这个 helper 缺失或被覆盖了。 - 类似的
__namehelper 问题在其他 esbuild 消费者中也有报告,当 helper 缺失或被重写时就会出现。
回归历史
2871657e(2026-01-06):脚本从 Bun 改为 tsx,让 Bun 变成可选依赖。- 在那之前(Bun 路径),
openclaw status和gateway:watch都能正常工作。
临时解决方案
-
开发脚本改回 Bun(目前的临时回退方案)。
-
用 Node + tsc watch,然后跑编译后的输出:
pnpm exec tsc --watch --preserveWatchOutput node --watch openclaw.mjs status -
本地确认:
pnpm exec tsc -p tsconfig.json+node openclaw.mjs status在 Node 25 上正常。 -
如果可以的话,在 TS loader 中禁用 esbuild 的 keepNames(阻止
__namehelper 注入);但 tsx 目前没暴露这个选项。 -
在 Node LTS(22/24)上测试
tsx,看问题是否只在 Node 25 出现。
参考链接
- https://opennext.js.org/cloudflare/howtos/keep_names
- https://esbuild.github.io/api/#keep-names
- https://github.com/evanw/esbuild/issues/1031
后续计划
- 在 Node 22/24 上复现,确认是否是 Node 25 的回归。
- 测试
tsxnightly 或回退到更早的版本(如果有已知回归的话)。 - 如果在 Node LTS 上也能复现,带着
__name堆栈信息向上游提交最小复现。