OpenClaw 2026.9.x 升级连环坑:no such column workspace_dir / state-migrated-no-rollback / LaunchAgent environment wrapper needs validation 修复
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 重建即可。
TLDR
- 现象:升级 2026.9.3 失败,Gateway 起不来,通道无响应。日志(triage handoff)显示
reason: "runtime-verification-failed",doctor 停在no such column: workspace_dir。 - 根因(上游迁移 bug):2026.9.x 把 skill-workshop 的
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 停止。 - 修复:4 张
skill_workshop_*表全部是空的,直接删表 + 删旧索引,让 canonical DDL(CREATE TABLE IF NOT EXISTS+ 正确索引)按需重建。备份后零数据损失。 - 验证:
openclaw doctorEXIT 0 →openclaw gateway start→ Telegram / Feishurunning, connected→ 重跑openclaw update顺利升到 2026.9.3。
现象
openclaw update 输出里 doctor 阶段失败,诊断手稿(~/.openclaw/logs/support/openclaw-triage-prompt-*.md)记录:
{"result":{"status":"error","mode":"npm","reason":"openclaw doctor",
"before":{"version":"2026.9.2"},"after":{"version":"2026.9.2"},
"recovery":{"serviceRestartSafe":false,"reason":"runtime-verification-failed",...},
"steps":[{"name":"openclaw doctor","exitCode":1,...}]}}
doctor 的具体报错:
Failed migrating shared state database schema at /Users/chedong/.openclaw/state/openclaw.sqlite:
SQLite canonical index idx_skill_workshop_collection_reviews_workspace_time
failed for /Users/chedong/.openclaw/state/openclaw.sqlite: no such column: workspace_dir
openclaw status 只有 run error,通道 disconnected。
根因:workspace_dir 列在迁移路径里没人补
2026.9.x 的 skill-workshop canonical schema 把按「owner agent」组织的表改成了按「workspace 目录」组织:
| 表 | 旧结构(2026.9.2 DB 实际) | canonical(2026.9.3) |
|---|---|---|
skill_workshop_collection_reviews |
列 owner_agent_id NOT NULL;索引 idx_..._owner_time(owner_agent_id, create_time DESC, review_id) |
列 workspace_dir NOT NULL;索引 idx_..._workspace_time(workspace_dir, create_time DESC, review_id DESC) |
skill_workshop_proposals |
无 workspace_dir、无 claim_released_time |
新增 workspace_dir TEXT NOT NULL + claim_released_time INTEGER |
但迁移代码(dist/store-sqlite-record-*.js 的 ensureSkillWorkshopSchema)只做了:
db.exec(SCHEMA_SQL);
ensureColumn(db, "skill_workshop_proposals", "claim_released_time INTEGER");
db.exec(SCHEMA_SQL) 里是 CREATE TABLE IF NOT EXISTS,对已存在的表不会改列;ensureColumn 只补了 claim_released_time,漏了 workspace_dir。于是状态库启动迁移(dist/openclaw-state-db-*.js 的 ensureSchema)在 repairCanonicalSqliteIndexes 重建 canonical 索引时,对不存在的 workspace_dir 列建索引 → no such column。迁移拒绝继续,doctor EXIT 1,更新恢复按设计保持 Gateway 停止。
顺带一提:这个失败路径在日志里几乎看不到,
~/Library/LaunchAgents/ai.openclaw.gateway.plist把StandardErrorPath指到/dev/null,底层错误被吞掉,只看到「Gateway 没响应」。
修复:删掉空的 skill_workshop 表让 canonical 重建
先确认两张关键表都是空表(无数据,删了零损失):
-- 行数全部为 0
SELECT count(*) FROM skill_workshop_collection_reviews; -- 0
SELECT count(*) FROM skill_workshop_proposals; -- 0
SELECT count(*) FROM skill_workshop_proposal_events; -- 0
SELECT count(*) FROM skill_workshop_proposal_rollbacks; -- 0
备份后删表 + 删旧索引(注意 FK 依赖:先删 proposal_events / proposal_rollbacks,再删 proposals):
-- 先备份:cp ~/.openclaw/state/openclaw.sqlite ~/.openclaw/backups/
DROP INDEX IF EXISTS idx_skill_workshop_collection_reviews_owner_time;
DROP TABLE IF EXISTS skill_workshop_proposal_events;
DROP TABLE IF EXISTS skill_workshop_proposal_rollbacks;
DROP TABLE IF EXISTS skill_workshop_collection_reviews;
DROP TABLE IF EXISTS skill_workshop_proposals;
这些表属于 lazy additive tables,doctor / gateway 启动时不会立刻重建,但首次访问 skill-workshop store 时 ensureSkillWorkshopSchema 会用 canonical DDL(含 workspace_dir 列和正确索引)自动重建。所以删完直接跑:
openclaw doctor # EXIT 0,迁移通过
openclaw gateway start # LaunchAgent 重新 bootstrap
openclaw channels status # Telegram / Feishu: running, connected
修复后重跑 openclaw update,这次一路绿灯:
activating — openclaw doctor... ✓ (27.21s)
✅ OpenClaw updated to 2026.9.3 (from 2026.9.2).
Gateway: restarted and verified.
验证
openclaw --version→OpenClaw 2026.9.3 (1391f7c)openclaw status→ Gatewayreachable,LaunchAgentloaded · runningopenclaw channels status→ Feishu / Telegram 均running, connected
后续:2026.9.5 / 2026.9.6 两次升级又卡 Gateway(2026-09-20 / 2026-09-27 补记)
上次修好 2026.9.3 后,后续两次升级(2026.9.5、2026.9.6)又在 openclaw update 时把 Gateway 卡停。根因和上次不同——这次不是表结构漂移,而是插件 deferred 迁移死锁 + 新版服务机制校验。全程仍无需手工改 DB,openclaw 自带命令即可解。
TLDR
- 2026.9.5(错误码
state-migrated-no-rollback):升级后状态库里migration_runs有两条deferred-plugin-migration:feishu/:opencode记录pending,报Plugin "feishu"/"opencode" state migration is pending: Package convergence must wait until the updating parent releases its install records.,阻塞 doctor;而openclaw update repair又因主 agent 的 legacysessions.json已迁入 SQLite、拿不到「verified source index」而报Deferred plugin session import has no verified source index—— 两环互锁。解法:跑普通openclaw doctor让 inspection 自动 resolve 两条 pending(日志Deferred state migration completed for plugin ...),再openclaw doctor --fix清理 legacy session 残留,然后openclaw update收尾。 - 2026.9.6(Gateway
not loaded):升级后服务直接不在运行,两个新原因:① 官方插件版本漂移 —— feishu/opencode 停在 2026.9.5,Plugin version drift: 2 active official plugins not on gateway 2026.9.6,again 触发两条 deferred pending;② LaunchAgent environment wrapper 校验失败 —— 2026.9.6 新增 wrapper 机制,旧 plist 不通过校验,Service config issue: LaunchAgent environment wrapper needs validation; reinstall the Gateway service.。解法:openclaw plugins update feishu opencode升级插件(自动 resolve pending)→openclaw doctor --fix→openclaw gateway install --force重装服务 →openclaw gateway restart。
2026.9.5:state-migrated-no-rollback 两环死锁
openclaw update 输出:
openclaw doctor 失败(error state-migrated-no-rollback)
Plugin "feishu" state migration is pending: Package convergence must wait until the updating parent releases its install records. ...
Plugin "opencode" state migration is pending: ...
此时 migration_runs 里可以看到两条 pending 记录(~/.openclaw/state/openclaw.sqlite):
SELECT id, status, report_json FROM migration_runs
WHERE id LIKE 'deferred-plugin-migration:%';
-- 两条 status = 'pending'
这代表 feishu / opencode 两个已装插件包(openclaw-feishu-*、openclaw-opencode-provider-*)的 state migration 被推迟了:插件包版本与主包还没收敛,系统先把它们的迁移输入保留住,等 owner(doctor inspection)来 resolve。而 update recovery 想用 openclaw update repair 验证可运行安装时,需要为 deferred 插件重建 verified source index;但主 agent 的 legacy sessions.json 早已迁入 SQLite,readMigrationArtifactIdentity 拿不到原始文件,于是:
Deferred plugin session import has no verified source index.
两环互锁,update 无法证明安装可运行 → 按设计保持 Gateway 停止。
解法(全部是官方命令,无需动 DB):
openclaw doctor # inspection 自动 resolve 两条 pending
# [state-migrations] Deferred state migration completed for plugin "feishu".
# [state-migrations] Deferred state migration completed for plugin "opencode".
openclaw doctor --fix # canonicalize 2 行 legacy delivery 字段,legacy→SQLite
openclaw update # ✅ OpenClaw updated to 2026.9.5 (from 2026.9.5)
openclaw gateway restart # 原子重启(LaunchAgent)
openclaw health --json # ok: true
2026.9.6:插件版本漂移 + LaunchAgent environment wrapper
openclaw update 到 2026.9.6 后 Gateway 仍 not loaded。openclaw gateway status --deep 给出两个新信号:
Service config issue: LaunchAgent environment wrapper needs validation; reinstall the Gateway service.
Plugin version drift: 2 active official plugins not on gateway 2026.9.6
Fix: update each drifted plugin:
- openclaw plugins update feishu
- openclaw plugins update opencode
原因一:官方插件版本漂移。 feishu / opencode 停在 2026.9.5,主包已 2026.9.6,于是又生成了两条 deferred-plugin-migration pending(和 2026.9.5 同款死锁又触发一次)。先把插件升上来:
openclaw plugins update feishu opencode
# Updated feishu: 2026.9.5 -> 2026.9.6.
# Updated opencode: 2026.9.5 -> 2026.9.6.
# [state-migrations] Deferred state migration completed for plugin "feishu"/"opencode".
原因二:2026.9.6 新增 LaunchAgent environment wrapper。 新版要求 plist 带 environment wrapper,旧 plist 不通过校验 → 服务不被加载。需要重装服务:
openclaw doctor --fix # 顺带自动迁移 agent DB schema v21 -> v23
openclaw gateway install --force # 重装 LaunchAgent(含新版 env wrapper)
# Installed LaunchAgent: /Users/chedong/Library/LaunchAgents/ai.openclaw.gateway.plist
# 注意:日志位置从 /tmp/openclaw/ 改为 ~/Library/Logs/openclaw/gateway.log
openclaw gateway restart
openclaw health --json # ok: true
openclaw channels status # Feishu / Telegram: running, connected
经验:2026.9.x 系列每次
openclaw update后都要看三点 —— ①migration_runs有无新的deferred-plugin-migrationpending;② 有无Plugin version drift(插件落后于主包);③ Gateway 是否not loaded(新版本服务机制校验旧 plist 失败)。三者都可用openclaw doctor/plugins update/gateway install --force解,别手工删 migration_runs 行(那正是系统在保护迁移输入)。
命令速查
# 状态与日志
openclaw status
openclaw channels status
openclaw doctor # 迁移卡住时的诊断入口
openclaw update cleanup --dry-run # 更新成功后清理回滚包
# 定位 skill-workshop 表结构漂移
sqlite3 ~/.openclaw/state/openclaw.sqlite ".schema skill_workshop_collection_reviews"
sqlite3 ~/.openclaw/state/openclaw.sqlite "PRAGMA user_version;" # 15
# 修列缺失:删空表让 canonical DDL 重建(先备份,确认表全空)
# DROP INDEX idx_..._owner_time; DROP TABLE skill_workshop_*;
# 2026.9.5+:升级后 Gateway 卡停的通用排查(先看这三处,再决定命令)
sqlite3 ~/.openclaw/state/openclaw.sqlite \
"SELECT id,status FROM migration_runs WHERE id LIKE 'deferred-plugin-migration:%';" # pending?
openclaw gateway status --deep # Plugin version drift? Service config issue?
openclaw doctor # 自动 resolve deferred-plugin-migration pending
openclaw doctor --fix # 清理 legacy session 残留 + agent DB schema 自动迁移
openclaw plugins update feishu opencode # 官方插件落后于主包时先升插件
openclaw gateway install --force # 2026.9.6+ environment wrapper 校验失败时重装服务
openclaw gateway restart # 原子重启(绝不 stop-then-start)
openclaw health --json # ok: true 才算起来
注意:动状态库前先备份 ~/.openclaw/state/openclaw.sqlite;只删确认全空的表,有数据的表要先迁移/回填 workspace_dir。2026.9.x 升级后的 deferred-plugin-migration pending 记录是系统在保护迁移输入,不要手工删行——用 openclaw doctor / openclaw plugins update 让系统自行 resolve。