openclaw update连续 4 次失败在global install swap步骤:retained package tree changed / Installation recovery is unverified,而安装树事后与 pristine(npm pack 解包)逐字节一致。根因是 swap 的完整性扫描带一个 30s 绝对截止(MAX_SCAN_MS=3e4),本机 454MB / 35050 文件的安装树在冷缓存 + 并发 I/O 下扫不完 → 超时抛错 →previousRoot未定义 → 二次校验误报「树变了」。失败记录只显示错误尾部,真正的超时被截断吞掉,极难定位。绕过用npm install -g openclaw@2026.9.4,根治把MAX_SCAN_MS补丁到 120s(注意:每次升级 npm 会覆盖补丁,需重打)。
openclaw update 稳定卡在 global install swap exit 1,失败记录 stderrTail 只有 ...: retained package tree changed Installation recovery is unverified; inspect the installation and backups in /usr/local/lib/node_modules before restarting.createPackageIntegrityReader 用 MAX_SCAN_MS = 30s 的绝对 wall-clock 截止包住每个 I/O。完整扫描安装树:热缓存 13–16s、冷缓存 ~23s、真实更新条件(刚暂存 454MB 候选包 + 系统在扫新文件)>30s → 抛 Package rollback verification timed out。此刻 prepareBaseline 的 previousRoot 还是 undefined,restoreSwap 的二次校验 !previousRoot 就误报 retained package tree changed。失败记录把 errors 数组从尾部截断,根因那一行被吃掉,只剩 restoreSwap 的次级消息。npm install -g openclaw@2026.9.4。npm 11 默认挡 install scripts,要带 --allow-scripts=openclaw,... 或配 npm config set allow-scripts=...,否则 koffi 原生库 / bundled-plugins postinstall 不会跑。targetVersion 为空时报 plugin-target-unavailable(feishu/opencode 无显式 target)。手动 openclaw plugins update --all 与 @latest 把 feishu、opencode 升到 2026.9.4 后,openclaw update --dry-run 的插件解析即通过。channels.feishu.groupPolicy 必须是 open / disabled / allowlist / allowall,旧的 disable 值会让 gateway 拒绝启动。dist/update-runner-*.mjs 里的 const MAX_SCAN_MS = 3e4; 补丁为 120000(120s),cron 的 openclaw update --yes 下次才能真正过 swap。openclaw update 在 validating 阶段 7 项候选校验全过(global update 57.8s、migration rehearsal、doctor lint、config validation、plugin resolution、migration continuation、gateway canary 23s),然后 swap 失败:
一次 SSH 密钥轮换(旧钥换新钥 + 加口令 + 全节点部署)踩坑后的沉淀,主机信息已隐去。
ssh-add 报 “Could not open a connection to your authentication agent”,九成是 SSH_AUTH_SOCK 没指向 launchd agent 的 socket——agent 本身在跑,只是 shell 找不到它:
# 找到 launchd agent 的 socket(路径每次重启会变)
launchctl print gui/$(id -u) | grep SSH_AUTH_SOCK
# 带上 socket 加载钥匙并存入钥匙串
SSH_AUTH_SOCK=<上一步的路径> ssh-add --apple-use-keychain ~/.ssh/id_ed25519_current
配套三件事缺一不可:
ssh-keygen -p -f ~/.ssh/id_ed25519_current~/.ssh/config 加 Host * 段的 AddKeysToAgent yes + UseKeychain yes~/.zshrc 加 socket 自动恢复段(见下文第 4 节),否则新终端里 pdsh 等批量工具全部认证失败~/.ssh/config 只显式指定当下该用的 IdentityFile。ssh-keygen -p -f ~/.ssh/id_ed25519_current
# 输入旧口令(无则直接回车) → 输两次新口令
验证口令已生效(能无口令派生公钥说明还是裸钥):
2026 年 9 月起,Homebrew 停止提供 Intel (x86_64) 的预编译 bottle。对 Intel Mac 用户意味着:任何没有预编译包的 formula,每次升级都要在本机源码编译。实测 rust 类程序在 8GiB 内存的机器上编译常报 SIGSEGV 栈溢出,llvm 等大依赖一次要编译很久。
替代方案 MacPorts 2.12.6 仍持续发布 x86_64 预编译二进制包。将重编译型软件迁到 MacPorts,brew 只留小工具,是一条可行的路。本文整理多台 Intel Mac 迁移的完整经验。
核心原则:MacPorts 有预编译 archive 才迁移;需要源码编译的保留 brew 版。另有一类根本不进系统包管理器——语言生态自带的官方工具链(Python 的 uv、Rust 的 rustup 等),见下文。
archive 探测(200 即迁,404 则保留):
curl -sI -o /dev/null -w "%{http_code}\n" \
https://packages.macports.org/eza/eza-0.23.5_0.darwin_24.x86_64.tbz2
_0 是 port revision,可能为 _1/_2。404 不一定是没有:
ripgrep-15.2.0_0+pcre.darwin_24.x86_64.tbz2、wget-1.25.0_1+gnutls.darwin_24.x86_64.tbz2。裸文件名探 404,加上 variant 就是 200。port install 会自动选择默认 variant,无需手动加。https://packages.macports.org/<port>/,能列出全部可用 archive 文件名。| brew | MacPorts 端口 |
|---|---|
| python@3.14 | python314 |
| go | go-1.27(无裸名端口) |
| httpd | apache2 |
| node@22 | nodejs22 |
| mysql-client@8.4 | mysql9(等官方二进制) |
| imagemagick | ImageMagick7 |
| ffmpeg | ffmpeg(+gpl2 variant 才有完整编解码) |
批量迁移要全自动,给 port 开 NOPASSWD(只限这一条命令):
openclaw update升 2026.9.3 时openclaw doctor卡在状态库迁移:SQLite canonical index idx_skill_workshop_collection_reviews_workspace_time failed ... no such column: workspace_dir。更新恢复机制按设计保持 Gateway 停止,于是 Telegram / Feishu 全部无响应。根因是 2026.9.x 迁移代码只补了claim_released_time列、漏补workspace_dir列;把两张空的 skill_workshop 表删掉让 canonical DDL 重建即可。
reason: "runtime-verification-failed",doctor 停在 no such column: workspace_dir。skill_workshop_collection_reviews 表从 owner_agent_id 列改成 workspace_dir 列(proposals 表新增 workspace_dir NOT NULL + claim_released_time),但迁移代码 ensureSkillWorkshopSchema 只执行了 ensureColumn(..., "claim_released_time INTEGER"),没有补 workspace_dir。随后 repairCanonicalSqliteIndexes 重建 canonical 索引 idx_..._workspace_time ON (workspace_dir, ...) 时列不存在 → 抛错 → doctor 拒绝继续 → 更新恢复保持 Gateway 停止。skill_workshop_* 表全部是空的,直接删表 + 删旧索引,让 canonical DDL(CREATE TABLE IF NOT EXISTS + 正确索引)按需重建。备份后零数据损失。openclaw doctor EXIT 0 → openclaw gateway start → Telegram / Feishu running, connected → 重跑 openclaw update 顺利升到 2026.9.3。openclaw update 输出里 doctor 阶段失败,诊断手稿(~/.openclaw/logs/support/openclaw-triage-prompt-*.md)记录:
feat: cache-bust CSS/JS with version query + improve MCP search description
- src/web_header.php: phpman.css?v=PHPMAN_VERSION
- src/web_footer.php: phpman.js?v=PHPMAN_VERSION
- src/mcp_server.php: cli_search description — mention FTS5 full-text,
cross-source search (man/perldoc/info/pydoc/ri), Perl module support
- src/mcp_server.php: instructions — search examples with :: modules
Server-side .htaccess (manual):
<FilesMatch '\.(css|js)$'>
Header set Cache-Control 'public, max-age=31536000, immutable'
</FilesMatch>
Co-Authored-By: Claude Code deepseek-v4-pro <noreply@taotoken.net>
OpenClaw 2026.8.1 升级后 Gateway 反复重启,
openclaw doctor报invalid persisted session row requires repair,Telegram bot 一直没反应。排查到最后发现:Telegram 无响应的真正原因和doctor --fix卡住的其实是同一个东西——未迁移的 legacyexec-approvals.json触发了ExecApprovalsMigrationRequiredError门卫,所有 exec-approvals 消费者(含 telegram 通道)拒绝启动。本文记录完整排查与修复过程。
session_nodes 表里残留了 2 条窗口缺失的 :run: 别名行(entry_json='{}'),openclaw doctor --fix 会先触发自己的校验守卫报 invalid persisted session row,没法自助修复。手动删掉这 2 条即可。~/.openclaw/agents/main/sessions/sessions.json 需要迁移,跑 openclaw doctor --session-sqlite import 导入。~/.openclaw/exec-approvals.json 没迁移到 SQLite。assertNoPendingLegacyExecApprovals 门卫在启动时检查这个文件,存在就抛 ExecApprovalsMigrationRequiredError,Telegram 通道起不来,日志里只看到 auto-restart attempt N/10 无限循环——底层错误被 LaunchAgent 的 StandardErrorPath=/dev/null 吞掉了。把 legacy 文件导入 state DB 的 exec_approvals_config 表并改名为 .migrated 后,Gateway 健康监控自动拉起 Telegram,恢复响应。升级到 OpenClaw 2026.8.1 后,openclaw doctor 报错:
docs: CLAUDE.md 分支约定 — 明确 master 为主干,勿 push 其他分支名
docs: CLAUDE.md 分支约定 — default 计划统一为 main(过渡期仍 push master)
fix: showForm 传入 markdown/json URL 修复 not-found 兜底链接失效
Codex 里给 GitHub MCP server 配好 bearer_token_env_var 后,仍报 Environment variable CODEX_GITHUB_PERSONAL_ACCESS_TOKEN ... is not set。根因:bearer_token_env_var 读的是 codex 自身进程 的环境变量,而把 token 塞进 ~/.codex/config.toml 的 [shell_environment_policy.set] 只注入它派生的 shell,到不了自身进程。正确做法是把环境变量 export 到 ~/.zshrc,在启动 codex 前就位。
按 GitHub MCP server 官方指南配好 [mcp_servers.github],codex 启动时仍报:
⚠ MCP client for `github` failed to start: MCP startup failed: Environment variable CODEX_GITHUB_PERSONAL_ACCESS_TOKEN for MCP server 'github' is not set
两个事实叠加:
| 事实 | 说明 |
|---|---|
Codex 不支持 inline bearer_token |
MCP server 配置只认 bearer_token_env_var,官方 schema 已把 inline bearer_token 字段隐藏(openai/codex #19294) |
bearer_token_env_var 读的是自身进程环境 |
它存的是「去哪个环境变量取 token」的名字,codex 连接时从自身进程读,不是从它派生的 bash 读 |
打个比方(仅为帮助理解):bearer_token_env_var 是一块「钥匙放在 X 口袋里」的告示牌,codex 只会翻自己的口袋(自身进程环境)。而 [shell_environment_policy.set] 是把钥匙塞进它派生的子进程口袋——塞错了地方。