概述 / Summary
我在 macOS 本地环境中,使用:
将 OpenClaw 从 2026.4.15 升级到 2026.4.21 后,升级没有正常完成,并引发了一次本地实例不可用的事故。
After upgrading OpenClaw from 2026.4.15 to 2026.4.21 on macOS using:
the upgrade did not complete cleanly and caused the local instance to become unhealthy.
这次事故不是单一报错,而是两个问题叠加导致的:
- bundled / extension 运行时依赖缺失
openclaw doctor --fix 在失败路径上把当前有效配置改写成了不完整的最小配置
This incident was not caused by a single error, but by two stacked problems:
- missing bundled / extension runtime dependencies
openclaw doctor --fix rewriting the active valid config into an incomplete minimal config on a failure path
起因 / Initial failure
升级到 2026.4.21 后,OpenClaw 在加载 Feishu 扩展运行时代码时,会直接依赖:
但这个依赖当时并没有随升级后的全局安装环境完整落地。
After upgrading to 2026.4.21, the Feishu extension runtime attempted to load:
but that dependency was not actually present in the installed global/runtime environment.
此时执行:
会直接报错:
Cannot find module '@larksuiteoapi/node-sdk'
Running:
failed with:
Cannot find module '@larksuiteoapi/node-sdk'
这说明第一层问题是:升级后的运行时依赖不完整,至少缺少 Feishu 扩展所需的 @larksuiteoapi/node-sdk。
This indicates the first issue: the post-upgrade runtime environment was incomplete, at minimum missing @larksuiteoapi/node-sdk, which is required by the Feishu extension.
事故经过 / What happened next
在 doctor --fix 失败之后,我检查发现当前配置文件:
~/.openclaw/openclaw.json
被缩成了一个非常小的“最小配置”,只剩下 gateway auth、meta 等少量字段。
After doctor --fix failed, I found that the active config file:
~/.openclaw/openclaw.json
had been reduced to a very small “minimal config”, containing only a few fields such as gateway auth and meta.
原本完整配置中的很多关键部分已经不在当前文件里,例如:
gateway.mode
- Telegram 配置
- Feishu 配置
- iMessage 配置
- agents / 其他原有运行配置
Many important parts from the original full config were no longer present in the active file, including:
gateway.mode
- Telegram configuration
- Feishu configuration
- iMessage configuration
- agents / other existing runtime configuration
随后再执行:
Gateway 无法正常启动,并出现:
Gateway start blocked: existing config is missing gateway.mode
After that, running:
did not recover the service. Instead, Gateway refused to start with:
Gateway start blocked: existing config is missing gateway.mode
也就是说,第二层问题并不是“Gateway 启动慢”或“端口占用”,而是:
当前活动配置已经被写成了缺少关键字段的损坏状态,OpenClaw 正确地拒绝用这份配置启动。
So the second issue was not “slow startup” or “port conflict”; rather:
the active config had been rewritten into a damaged state missing required fields, and OpenClaw correctly refused to start with it.
实际根因 / Root cause
从这次排障过程看,根因是两部分叠加:
[email protected] 升级后,bundled plugin / extension 所需的运行时依赖没有完整落地
- 失败的修复流程把
~/.openclaw/openclaw.json 改写成了不完整配置,导致后续 Gateway 启动被阻断
Based on the recovery process, the root cause appears to be a combination of:
[email protected] not leaving all required bundled plugin / extension runtime dependencies properly installed after upgrade
- a failed recovery path rewriting
~/.openclaw/openclaw.json into an incomplete config, which then blocked Gateway startup
更具体地说:
- 第一层:Feishu 扩展运行时依赖缺失
- 第二层:
doctor --fix 的失败路径没有做到“要么成功修复、要么完全不动原配置”
More specifically:
- first layer: missing Feishu extension runtime dependency
- second layer: the failure path around
doctor --fix did not behave transactionally (“either fix successfully, or leave the original config untouched”)
处理过程 / Recovery steps
我是这样恢复的:
- 先手动补装缺失依赖:
npm install -g @larksuiteoapi/node-sdk
- 检查发现备份文件仍然存在:
~/.openclaw/openclaw.json.bak
-
备份文件中保留了原本完整的配置,包括:
gateway.mode=local
- Telegram 配置
- iMessage 配置
- Feishu 配置
- agents 配置
-
将完整备份恢复回:
~/.openclaw/openclaw.json
同时保留当前生成的 gateway auth 设置,避免 token / auth 状态不一致。
- 恢复后重新执行:
这次可以继续运行,并自动补装了缺失的 bundled plugin runtime dependencies,包括:
@larksuiteoapi/node-sdk
grammy
@grammyjs/runner
@grammyjs/transformer-throttler
@pierre/diffs
@pierre/theme
- 随后重新安装并重启 Gateway:
openclaw gateway install --force
openclaw gateway restart
I recovered the environment as follows:
- manually installed the missing dependency:
npm install -g @larksuiteoapi/node-sdk
- confirmed the backup config still existed:
~/.openclaw/openclaw.json.bak
-
verified that the backup still contained the original full config, including:
gateway.mode=local
- Telegram config
- iMessage config
- Feishu config
- agents config
-
restored the full backup into:
~/.openclaw/openclaw.json
while preserving the current gateway auth settings, so token/auth state would remain consistent.
- re-ran:
This time it succeeded and automatically installed missing bundled plugin runtime dependencies, including:
@larksuiteoapi/node-sdk
grammy
@grammyjs/runner
@grammyjs/transformer-throttler
@pierre/diffs
@pierre/theme
- then reinstalled and restarted Gateway:
openclaw gateway install --force
openclaw gateway restart
恢复后的验证 / Validation after recovery
最后执行:
openclaw gateway status --deep
结果显示:
Connectivity probe: ok
Capability: admin-capable
Listening: *:18789
Finally, I ran:
openclaw gateway status --deep
and got:
Connectivity probe: ok
Capability: admin-capable
Listening: *:18789
这说明在“补齐缺失依赖 + 恢复完整配置 + 重装并重启 Gateway”之后,实例已经恢复正常。
This shows that after restoring missing dependencies, restoring the full config, and reinstalling/restarting Gateway, the instance returned to a healthy state.
当前状态补充 / Additional note about current state
按我的需要,恢复完成后我又执行了:
并确认:
lsof -nP -iTCP:18789 -sTCP:LISTEN
没有进程继续监听 18789。
After recovery, I intentionally ran:
and confirmed with:
lsof -nP -iTCP:18789 -sTCP:LISTEN
that nothing was listening on port 18789.
所以“当前 Gateway 已停止”是我主动执行的结果,不属于本次事故的一部分。
So the fact that Gateway is currently stopped was intentional after recovery, and is not part of the incident itself.
期望行为 / Expected behavior
我认为以下行为才是更合理、安全的:
openclaw update 不应该把 bundled extension/plugin 的运行时依赖遗漏掉
openclaw doctor --fix 不应该在失败路径上把当前有效配置改写成无效最小配置
- 如果修复失败,应该保留原配置不动,而不是留下一个缺字段的 active config
- 对
gateway.mode 这种关键字段,应该在写回前显式校验
- 配置修复流程应该具备事务性和回滚保护
I believe the expected behavior should be:
openclaw update should not leave bundled extension/plugin runtime dependencies missing
openclaw doctor --fix should never rewrite a valid active config into an invalid minimal config on a failure path
- if recovery fails, the previous valid config should remain untouched
- required fields such as
gateway.mode should be explicitly validated before write
- config repair should be transactional and rollback-safe
建议修复方向 / Suggested fixes
1. 发布/安装链路校验 / Packaging and install validation
建议在 release / install / update 流程中增加校验,确保 bundled plugin 所需运行时依赖完整存在。
Suggested: add validation in release / install / update flows to ensure all bundled plugin runtime dependencies are actually present.
例如可以增加:
- 对 Feishu 扩展运行时依赖的 smoke test
- 对 Telegram 相关运行时依赖的 smoke test
- 升级完成后的依赖完整性检查
- 对 bundled plugin 入口进行一次实际 require/import 验证
For example:
- smoke tests for Feishu extension runtime deps
- smoke tests for Telegram-related runtime deps
- dependency completeness checks after upgrade
- real require/import validation for bundled plugin entrypoints
2. doctor --fix 的安全性 / Safer doctor --fix behavior
建议让 doctor --fix 的配置写回过程具备事务性:
- 先生成候选配置
- 完整校验候选配置
- 只有在校验通过时才替换当前 active config
- 如果校验失败,则保留原文件并明确报错
Suggested: make config rewrite during doctor --fix transactional:
- generate candidate config
- fully validate candidate config
- replace the active config only if validation passes
- if validation fails, keep the original file untouched and surface a clear error
此外应特别保护关键字段,例如:
gateway.mode
gateway.bind
- channels
- agents
- auth / session related required blocks
It would also help to explicitly protect critical fields such as:
gateway.mode
gateway.bind
- channels
- agents
- auth / session-related required blocks
3. 备份与恢复提示 / Backup and recovery UX
如果 .bak 可用,CLI 应明确提示用户可以直接恢复。
如果准备把现有完整配置覆盖成“最小配置”,应在执行前有非常明确的风险提示,甚至默认禁止。
If .bak exists, the CLI should explicitly tell the user it can be used for recovery.
If the tool is about to overwrite an existing full config with a “minimal config”, it should issue a very strong warning—or ideally refuse by default.
4. 错误分层更清晰 / Better error separation
这次事故里,用户侧看到的是多个阶段的不同问题叠在一起:
- 依赖缺失
doctor --fix 失败
- 配置被缩坏
- Gateway 因缺少
gateway.mode 拒绝启动
In this incident, the user-visible failures were layered:
- missing dependency
doctor --fix failure
- config being collapsed into an incomplete state
- Gateway refusing to start because
gateway.mode was missing
建议在 CLI 输出里把这些阶段明确区分,避免用户误以为只是单纯“Gateway 没启动起来”。
It would help if CLI output separated these phases clearly, instead of making it look like “Gateway just failed to start”.
环境 / Environment
- Upgrade path:
2026.4.15 -> 2026.4.21
- Update command:
openclaw update
- OS: macOS
- Affected area:
- bundled plugin runtime dependencies
doctor --fix recovery path
- config safety / config rewrite
- gateway startup validation
如需补充 / If helpful
如果维护者需要,我可以再补充以下材料(可脱敏):
openclaw.json 被缩成最小配置前后的结构差异
.bak 恢复后的配置字段对比
- 当时的完整报错日志
doctor --fix 自动补装依赖时的输出
If helpful, I can also provide additional redacted materials:
- before/after structure of
openclaw.json when it was collapsed into a minimal config
- config field differences after restoring from
.bak
- the full error logs
- the dependency-install output from the successful
doctor --fix
概述 / Summary
我在 macOS 本地环境中,使用:
将 OpenClaw 从
2026.4.15升级到2026.4.21后,升级没有正常完成,并引发了一次本地实例不可用的事故。After upgrading OpenClaw from
2026.4.15to2026.4.21on macOS using:the upgrade did not complete cleanly and caused the local instance to become unhealthy.
这次事故不是单一报错,而是两个问题叠加导致的:
openclaw doctor --fix在失败路径上把当前有效配置改写成了不完整的最小配置This incident was not caused by a single error, but by two stacked problems:
openclaw doctor --fixrewriting the active valid config into an incomplete minimal config on a failure path起因 / Initial failure
升级到
2026.4.21后,OpenClaw 在加载 Feishu 扩展运行时代码时,会直接依赖:但这个依赖当时并没有随升级后的全局安装环境完整落地。
After upgrading to
2026.4.21, the Feishu extension runtime attempted to load:but that dependency was not actually present in the installed global/runtime environment.
此时执行:
会直接报错:
Running:
failed with:
这说明第一层问题是:升级后的运行时依赖不完整,至少缺少 Feishu 扩展所需的
@larksuiteoapi/node-sdk。This indicates the first issue: the post-upgrade runtime environment was incomplete, at minimum missing
@larksuiteoapi/node-sdk, which is required by the Feishu extension.事故经过 / What happened next
在
doctor --fix失败之后,我检查发现当前配置文件:被缩成了一个非常小的“最小配置”,只剩下 gateway auth、meta 等少量字段。
After
doctor --fixfailed, I found that the active config file:had been reduced to a very small “minimal config”, containing only a few fields such as gateway auth and meta.
原本完整配置中的很多关键部分已经不在当前文件里,例如:
gateway.modeMany important parts from the original full config were no longer present in the active file, including:
gateway.mode随后再执行:
Gateway 无法正常启动,并出现:
After that, running:
did not recover the service. Instead, Gateway refused to start with:
也就是说,第二层问题并不是“Gateway 启动慢”或“端口占用”,而是:
当前活动配置已经被写成了缺少关键字段的损坏状态,OpenClaw 正确地拒绝用这份配置启动。
So the second issue was not “slow startup” or “port conflict”; rather:
the active config had been rewritten into a damaged state missing required fields, and OpenClaw correctly refused to start with it.
实际根因 / Root cause
从这次排障过程看,根因是两部分叠加:
[email protected]升级后,bundled plugin / extension 所需的运行时依赖没有完整落地~/.openclaw/openclaw.json改写成了不完整配置,导致后续 Gateway 启动被阻断Based on the recovery process, the root cause appears to be a combination of:
[email protected]not leaving all required bundled plugin / extension runtime dependencies properly installed after upgrade~/.openclaw/openclaw.jsoninto an incomplete config, which then blocked Gateway startup更具体地说:
doctor --fix的失败路径没有做到“要么成功修复、要么完全不动原配置”More specifically:
doctor --fixdid not behave transactionally (“either fix successfully, or leave the original config untouched”)处理过程 / Recovery steps
我是这样恢复的:
备份文件中保留了原本完整的配置,包括:
gateway.mode=local将完整备份恢复回:
同时保留当前生成的 gateway auth 设置,避免 token / auth 状态不一致。
这次可以继续运行,并自动补装了缺失的 bundled plugin runtime dependencies,包括:
@larksuiteoapi/node-sdkgrammy@grammyjs/runner@grammyjs/transformer-throttler@pierre/diffs@pierre/themeI recovered the environment as follows:
verified that the backup still contained the original full config, including:
gateway.mode=localrestored the full backup into:
while preserving the current gateway auth settings, so token/auth state would remain consistent.
This time it succeeded and automatically installed missing bundled plugin runtime dependencies, including:
@larksuiteoapi/node-sdkgrammy@grammyjs/runner@grammyjs/transformer-throttler@pierre/diffs@pierre/theme恢复后的验证 / Validation after recovery
最后执行:
结果显示:
Connectivity probe: okCapability: admin-capableListening: *:18789Finally, I ran:
and got:
Connectivity probe: okCapability: admin-capableListening: *:18789这说明在“补齐缺失依赖 + 恢复完整配置 + 重装并重启 Gateway”之后,实例已经恢复正常。
This shows that after restoring missing dependencies, restoring the full config, and reinstalling/restarting Gateway, the instance returned to a healthy state.
当前状态补充 / Additional note about current state
按我的需要,恢复完成后我又执行了:
并确认:
没有进程继续监听
18789。After recovery, I intentionally ran:
and confirmed with:
that nothing was listening on port
18789.所以“当前 Gateway 已停止”是我主动执行的结果,不属于本次事故的一部分。
So the fact that Gateway is currently stopped was intentional after recovery, and is not part of the incident itself.
期望行为 / Expected behavior
我认为以下行为才是更合理、安全的:
openclaw update不应该把 bundled extension/plugin 的运行时依赖遗漏掉openclaw doctor --fix不应该在失败路径上把当前有效配置改写成无效最小配置gateway.mode这种关键字段,应该在写回前显式校验I believe the expected behavior should be:
openclaw updateshould not leave bundled extension/plugin runtime dependencies missingopenclaw doctor --fixshould never rewrite a valid active config into an invalid minimal config on a failure pathgateway.modeshould be explicitly validated before write建议修复方向 / Suggested fixes
1. 发布/安装链路校验 / Packaging and install validation
建议在 release / install / update 流程中增加校验,确保 bundled plugin 所需运行时依赖完整存在。
Suggested: add validation in release / install / update flows to ensure all bundled plugin runtime dependencies are actually present.
例如可以增加:
For example:
2. doctor --fix 的安全性 / Safer doctor --fix behavior
建议让
doctor --fix的配置写回过程具备事务性:Suggested: make config rewrite during
doctor --fixtransactional:此外应特别保护关键字段,例如:
gateway.modegateway.bindIt would also help to explicitly protect critical fields such as:
gateway.modegateway.bind3. 备份与恢复提示 / Backup and recovery UX
如果
.bak可用,CLI 应明确提示用户可以直接恢复。如果准备把现有完整配置覆盖成“最小配置”,应在执行前有非常明确的风险提示,甚至默认禁止。
If
.bakexists, the CLI should explicitly tell the user it can be used for recovery.If the tool is about to overwrite an existing full config with a “minimal config”, it should issue a very strong warning—or ideally refuse by default.
4. 错误分层更清晰 / Better error separation
这次事故里,用户侧看到的是多个阶段的不同问题叠在一起:
doctor --fix失败gateway.mode拒绝启动In this incident, the user-visible failures were layered:
doctor --fixfailuregateway.modewas missing建议在 CLI 输出里把这些阶段明确区分,避免用户误以为只是单纯“Gateway 没启动起来”。
It would help if CLI output separated these phases clearly, instead of making it look like “Gateway just failed to start”.
环境 / Environment
2026.4.15 -> 2026.4.21openclaw updatedoctor --fixrecovery path如需补充 / If helpful
如果维护者需要,我可以再补充以下材料(可脱敏):
openclaw.json被缩成最小配置前后的结构差异.bak恢复后的配置字段对比doctor --fix自动补装依赖时的输出If helpful, I can also provide additional redacted materials:
openclaw.jsonwhen it was collapsed into a minimal config.bakdoctor --fix