OpenClaw 升级后 Telegram 无响应:修复 invalid persisted session row 与 Legacy exec approvals 迁移
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 通道)拒绝启动。本文记录完整排查与修复过程。
TLDR
- session 损坏:
session_nodes表里残留了 2 条窗口缺失的:run:别名行(entry_json='{}'),openclaw doctor --fix会先触发自己的校验守卫报invalid persisted session row,没法自助修复。手动删掉这 2 条即可。 - legacy session store:老的
~/.openclaw/agents/main/sessions/sessions.json需要迁移,跑openclaw doctor --session-sqlite import导入。 - Telegram 无响应(真凶):
~/.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 报错:
invalid persisted session row requires repair for
agent:main:cron:9638dbe1-...:run:d49e1a0d-...;
stop the Gateway and run openclaw doctor --fix
Gateway 日志里 Telegram 通道反复重启,但看不到任何底层原因:
[telegram] [default] starting provider (@chedong1Bot)
auto-restart attempt 1/10 in ...
auto-restart attempt 10/10 in ...
health-monitor restarting (reason: gave-up)
根因 1:session_nodes 残留窗口缺失的别名行
session_nodes 表以 session_key 为主键。每行有一个 current_session_id 指向 session_windows 表里的窗口(session_id + session_key)。一条 entry_json='{}' 的行只有在其窗口 session_id = current_session_id 且 session_key 一致时才是合法的;否则就是损坏行。
这次损坏的是两条 cron 任务的 :run: 别名行——父行(cron:xxx → current: run:xxx)完好,但多出了一条窗口缺失的 {} 行。openclaw doctor --fix 在 2026.8.1 里的修复路径会先经过 scanCanonicalSqliteSessionEntries 校验守卫,自己把自己挡在外面(抛 SessionCanonicalKeyMigrationRequiredError),无法自助修复。
修复 1:手动删除窗口缺失的 {} 行
停掉 Gateway 后,在 agent 数据库里定位并删除这两条行(只删窗口缺失的别名行,父行保留):
-- 定位:entry_valid=-1 且无匹配窗口的行
SELECT session_key, current_session_id, entry_valid, status
FROM session_nodes
WHERE entry_valid = -1;
-- 复核:该 current_session_id 在 session_windows 里没有匹配记录
SELECT session_id, session_key FROM session_windows
WHERE session_id = 'd49e1a0d-7d75-4465-8858-deb00a90dfae'
AND session_key = 'agent:main:cron:9638dbe1-...:run:d49e1a0d-...';
DELETE FROM session_nodes
WHERE session_key = 'agent:main:cron:9638dbe1-...:run:d49e1a0d-...';
根因 2:legacy session store 未迁移
老版本(Session Store JSON)还在 ~/.openclaw/agents/main/sessions/sessions.json,需要迁移到 SQLite。2026.8.1 提供了官方命令。
修复 2:openclaw doctor --session-sqlite import
openclaw doctor --session-sqlite import
# 导入 6 条目 / 3920 事件,归档未被引用的 JSONL
根因 3(Telegram 无响应的真凶):legacy exec-approvals 门卫
Session 修完后 Gateway 起来了,openclaw doctor 也 EXIT 0,但 Telegram 还是没反应。openclaw channels status 给出了真相:
- Telegram default: enabled, configured,
error:Legacy exec approvals exist at /Users/chedong/.openclaw/exec-approvals.json.
Run `openclaw doctor --fix` before using exec approvals.,
stopped, disconnected
assertNoPendingLegacyExecApprovals 是 exec-approvals 的迁移门卫:只要 legacy ~/.openclaw/exec-approvals.json 还存在,就抛 ExecApprovalsMigrationRequiredError。Telegram 通道启动时也走 exec-approvals,所以被一并挡住。而 openclaw doctor --fix 本身也卡在同一个门卫上(CLI init gate),形成死锁:只有 doctor –fix 能迁移,但 doctor –fix 先被门卫拦住。
日志里看不到这个错误,是因为 LaunchAgent 的 plist 把 stderr 丢掉了:
<key>StandardErrorPath</key><string>/dev/null</string>
修复 3:把 legacy exec-approvals 导入 SQLite
迁移的实质是两条:
- 把 legacy 文件内容写进 state DB 的
exec_approvals_config表(config_key='current',raw_json为JSON.stringify(file, null, 2) + "\n",以及socket_path/has_socket_token/agent_count/allowlist_count等投影列); - 把 legacy 文件改名为
exec-approvals.json.migrated,让pathMayExist探针放行。
openclaw doctor --fix 做不了这个,所以写了个幂等的迁移脚本(关键表结构):
CREATE TABLE IF NOT EXISTS "exec_approvals_config" (
config_key TEXT NOT NULL PRIMARY KEY,
raw_json TEXT NOT NULL,
socket_path TEXT,
has_socket_token INTEGER NOT NULL,
default_security TEXT,
default_ask TEXT,
default_ask_fallback TEXT,
auto_allow_skills INTEGER,
agent_count INTEGER NOT NULL,
allowlist_count INTEGER NOT NULL,
updated_at_ms INTEGER NOT NULL
) STRICT;
迁移后验证:
INSERTED exec_approvals_config: agent_count=1, allowlist_count=3
DB VERIFY: current|1|3|1|1237
channels status 立即可见 Telegram 恢复:
- Telegram default: enabled, configured, running, connected,
transport: just now, mode:polling
Gateway 不需要手动重启——健康监控发现门卫释放后会自动拉起通道。
验证
openclaw channels status:Feishu / Telegram 均running, connectedopenclaw doctor:EXIT 0- 之前被门卫挡掉的 WS 命令(
agents.list、commands.list)恢复 - Telegram bot 正常收发消息
命令速查
# 通道健康
openclaw channels status
# 定位 session_nodes 损坏行
sqlite3 ~/.openclaw/agents/main/agent/openclaw-agent.sqlite \
"SELECT session_key, current_session_id, entry_valid, status \
FROM session_nodes WHERE entry_valid = -1;"
# 复核窗口是否缺失
sqlite3 ~/.openclaw/agents/main/agent/openclaw-agent.sqlite \
"SELECT session_id, session_key FROM session_windows \
WHERE session_id = '<current_session_id>' \
AND session_key = '<session_key>';"
# 迁移 legacy session store
openclaw doctor --session-sqlite import
# 迁移 legacy exec-approvals(gateway 状态里的报错提示)
# 1. 写 exec_approvals_config 行(config_key='current')
# 2. 把 exec-approvals.json 改名 exec-approvals.json.migrated
# Gateway LaunchAgent 的 stderr 被丢到 /dev/null,
# 排查 provider 启动失败时先改 plist 把错误落盘
注意:涉及 session / exec-approvals 的修复都在改状态库,操作前先备份 ~/.openclaw/agents/main/agent/openclaw-agent.sqlite 和 ~/.openclaw/state/openclaw.sqlite。