OpenClaw 的版本升级表面上只是更新一个 npm 包,但当实例已经积累了大量会话、状态数据库、插件和运行时数据后,真正困难的部分往往不是“把新版本装上去”,而是如何让旧状态安全迁移到新版本,并确认整个实例仍然属于标准、可继续升级的安装形态。
下面记录一次从 OpenClaw 2026.9.3 升级到 2026.9.5 的完整实例升级过程。内容仅涉及升级本身,包括更新失败、手工安装、数据库迁移、插件同步、安装形态验证以及升级后的启动验证。
一、升级前状态
目标实例运行于 ARM64 Linux 环境,OpenClaw 原版本为:
OpenClaw 2026.9.3
安装方式属于标准 npm 全局 package 安装,核心程序位于系统级 Node.js 全局模块目录中,由 systemd user service 管理 Gateway。
实例已经长期运行,包含:
- 多个 Agent
- 大量历史 Sessions
- SQLite 状态数据库
- 外部插件
- 自定义 Workspace
- systemd Gateway 服务
这意味着升级不能简单地只观察:
openclaw --version
真正需要确认的是:
程序版本
数据库 Schema
插件版本
状态迁移
Gateway
Agent
Sessions
未来 updater
全部能够同时正常工作。
二、官方 updater 再次卡在数据库预检
首先使用标准升级入口:
openclaw update
但升级没有进入真正的软件包替换阶段,而是停止在:
database-schema-preflight
核心错误是 SQLite 只读快照操作超过约 30 秒:
SQLite read-only snapshot timed out after 30 seconds
最初容易怀疑是 Gateway 正在占用数据库。
因此停止 Gateway,并确认相关数据库没有其他明显使用者后重新运行 updater。
结果没有变化。
这说明问题并不是简单的:
Gateway 正在运行
→ 数据库锁住
→ updater 无法检查
而更接近:
旧版 updater
↓
数据库升级前预检
↓
只读 SQLite snapshot
↓
在当前实例规模和存储性能下超过固定超时时间
↓
整个更新被阻止
这种失败有一个重要特点:
OpenClaw 本身仍然可以正常运行,但 updater 在真正开始更新之前就已经退出。
因此,继续重复执行同一个 updater 并不会带来新的结果。
三、改用标准 npm 包直接安装 2026.9.5
既然实例本身就是 npm package 安装,下一步直接使用 npm 替换全局 OpenClaw 软件包:
/usr/bin/npm i -g openclaw@2026.9.5 --allow-scripts=openclaw
安装成功后,版本由:
OpenClaw 2026.9.3
变为:
OpenClaw 2026.9.5
这一步说明:
2026.9.5 的程序文件已经成功安装。
但这还不能等同于:
OpenClaw 实例已经升级完成。
因为程序文件和运行数据是两件不同的事情。
此时旧实例的 SQLite 数据仍然可能保持旧 Schema。
四、程序升级成功,但数据库仍然属于旧版本
安装 2026.9.5 后进行只读检查,发现 Agent 数据库仍然需要升级。
实例中两个主要 Agent SQLite 数据库当时仍然处于:
schema version 19
而 2026.9.5 需要的新状态格式已经进入:
schema version 21
因此出现了典型的升级中间态:
OpenClaw binary = 2026.9.5
但
OpenClaw data schema = older version
这个状态不能直接当成完成。
五、使用 Doctor 完成数据库正式迁移
在 Gateway 停止状态下运行:
OPENCLAW_SERVICE_REPAIR_POLICY=external openclaw doctor --fix
这里使用:
OPENCLAW_SERVICE_REPAIR_POLICY=external
目的是让 Doctor 处理实例数据和迁移,而不擅自接管外部已有的服务管理方式。
迁移过程并不快。
期间能够观察到:
- SQLite validation
- Agent DB open
- Session SQLite migration
- delayed state migration
- canonical validation
- index validation
- transaction lock wait
部分步骤耗时达到数秒甚至更长。
但最终两个 Agent 数据库都成功完成:
v19 → v21
这一步才真正完成了:
2026.9.3 数据状态
↓
2026.9.5 数据状态
的结构迁移。
六、确认 Session SQLite 已经没有遗留迁移项
数据库 Schema 升级完成后,继续运行 Session SQLite dry-run:
openclaw doctor \
--session-sqlite dry-run \
--session-sqlite-all-agents
最终返回:
0 target(s)
0 legacy entries
0 sqlite entries
0 issue(s)
这组结果非常重要。
它意味着当前已经不存在:
- 等待迁移的 legacy session
- 尚未完成的 SQLite session conversion
- 明确的 Session SQLite 异常项
因此数据库迁移可以视为真正完成,而不是“版本号已经改成 v21,但后台还留着迁移任务”。
七、处理插件版本漂移
程序和数据库完成升级后,Doctor 继续发现若干插件存在版本漂移:
installed: 2026.9.3
expected: 2026.9.5
这类情况并不奇怪。
OpenClaw 核心程序升级并不意味着所有独立插件都会自动同步到同一个版本。
因此分别对受影响插件执行更新。
典型形式为:
openclaw plugins update <plugin>
完成后,核心插件和外部插件统一进入 2026.9.5 兼容状态。
后续状态检查显示:
Plugin compatibility: none
也就是没有留下已知插件兼容性冲突。
八、一个关键问题:手工 npm 安装会不会破坏以后正常升级?
手工执行:
npm i -g openclaw@2026.9.5
以后,一个非常重要的问题是:
OpenClaw updater 还能否把这个实例识别成正常安装?
如果 updater 不再知道当前软件包由谁管理,那么虽然眼前能运行,未来每次升级都可能只能继续手工处理。
因此专门检查了安装形态。
1. CLI 仍然指向标准 npm 全局包
OpenClaw CLI 仍然通过系统标准入口调用全局 npm package。
结构类似:
system binary
↓
global node_modules
↓
openclaw package
没有出现:
- 自定义 wrapper
- 临时目录启动
- Git checkout 启动
- 手工复制 dist
- 非标准 launcher
2. npm 自己仍然识别这个包
执行全局包检查后,npm 能够正常看到:
openclaw@2026.9.5
也就是说:
npm package ownership 没有丢失。
3. OpenClaw updater 自己也识别为 package 安装
运行:
openclaw update status --json
能够看到类似:
installKind: package
packageManager: npm
channel: stable
这说明 OpenClaw 自己也没有把当前实例识别为未知来源。
九、最重要的验证:执行 updater dry-run
随后执行:
openclaw update --dry-run --json
这一步并不真正更新,而是让 updater 完整规划:
如果未来有新版本,现在这个实例会怎么升级?
dry-run 成功完成,并识别出:
currentVersion: 2026.9.5
targetVersion: 2026.9.5
installKind: package
mode: npm
updateInstallKind: package
effectiveChannel: stable
switchToGit: false
switchToPackage: false
这实际上证明了一个非常关键的结论:
直接通过 npm 安装 2026.9.5,并没有把实例变成“非官方安装”。
当前实例仍然属于:
standard npm package installation
以后仍然可以重新使用:
openclaw update
完成正常管理升级。
十、升级过程中暴露出的真正瓶颈:SQLite,而不是 npm
有意思的是,整个升级过程中最耗时间的并不是:
npm install
而是 SQLite。
多个阶段都出现了:
slow SQLite transaction
slow SQLite transaction lock wait
slow agent database open
slow canonical validation
slow session reclamation
部分 lock wait 达到数秒甚至十几秒。
一次 updater dry-run 本身就花费了数分钟。
这说明对于大型 OpenClaw 实例:
升级耗时往往取决于状态数据库,而不是程序包大小。
可以把升级过程抽象成:
安装代码
↓
打开状态数据库
↓
验证 Schema
↓
验证 Session
↓
建立/验证索引
↓
迁移状态
↓
插件同步
↓
启动 Gateway
越往后,SQLite 的影响越大。
十一、为什么 2026.9.5 能完成,而此前相近版本没有完成
此前曾对一个相邻版本尝试过相似的 npm 安装流程。
当时:
npm package replacement
本身也能完成,但后续:
database migration
startup validation
Gateway startup
没有最终进入稳定可用状态。
而 2026.9.5 在相同类型的机器、相同实例数据、相似存储环境下成功完成:
数据库迁移
Session validation
Gateway startup
运行验证
因此差异不能简单解释为:
“换了一种安装方法。”
真正发生变化的是目标版本本身。
换句话说:
npm installation
只负责替换程序。
真正决定一个 OpenClaw 实例能否完成升级的是:
目标版本对旧数据库的迁移能力
+
状态数据库容错
+
启动阶段的生命周期管理
+
超时策略
十二、升级后的第一次 Gateway 启动并不顺利
完成数据库和插件升级后启动 Gateway。
systemd 很快显示服务:
active
但这并不意味着 Gateway 已经真正可以接受连接。
随后客户端连接仍然出现:
ECONNREFUSED
查看启动日志后发现,Gateway 仍然处于初始化阶段。
十三、systemd active 不等于 Gateway ready
2026.9.5 的启动过程包含大量后台初始化。
典型顺序类似:
systemd starts process
↓
loading configuration
↓
resolving authentication
↓
spawn broker
↓
SQLite validation
↓
session reclamation
↓
starting HTTP server
↓
starting channels
↓
starting sidecars
↓
gateway ready
因此:
systemctl: active
只代表:
Node 主进程已经存在。
它并不代表:
HTTP server 已监听
更不代表:
整个 Gateway 已 ready
这也是升级验证时容易产生误判的地方。
十四、第一次启动出现 state-lifecycle contention
第一次完整启动过程中还出现过一次真正的启动失败:
StateDatabaseCoordinatorContentionError
错误信息指向:
another OpenClaw process owns state-lifecycle
随后 Gateway:
startup failed
systemd 记录主进程退出,并按照服务策略自动重新启动。
这个错误与普通的:
database is locked
不是完全同一类问题。
普通 SQLite lock contention 在此前多个阶段都可以:
wait
→ retry
→ recovered
而 state-lifecycle contention 属于 OpenClaw 自身数据库生命周期协调器检测到所有权冲突。
十五、第二次自动启动成功
systemd 自动重启后,第二轮启动最终完成。
启动过程大致表现为:
service started
↓
configuration loading
↓
authentication
↓
SQLite validation
↓
HTTP server
↓
channels and sidecars
↓
gateway ready
这一轮仍然很慢。
从 systemd 开始启动,到最终:
[gateway] ready
用了大约数分钟。
期间仍然出现:
slow SQLite reclamation
event loop delay
high event loop utilization
但这些问题最终没有导致第二次失败。
Gateway 成功进入:
http server listening
gateway ready
十六、最终实例状态验证
升级最终不是以:
npm install returned 0
作为成功标准。
而是以实际运行状态为标准。
最终普通状态检查显示:
OpenClaw 2026.9.5
Gateway reachable
Gateway service running
Agents loaded
Sessions loaded
Plugins compatible
Channels operational
其中能够正常读取:
- Agent
- Sessions
- Model
- Channel
- Plugin
- Gateway
- systemd service
状态。
这意味着升级后的实例已经完整恢复运行。
十七、最终升级链路
整个升级过程可以压缩成:
OpenClaw 2026.9.3
│
▼
openclaw update
│
└── database-schema-preflight timeout
│
▼
updater 无法继续
│
▼
npm install openclaw@2026.9.5
│
▼
程序升级到 2026.9.5
│
▼
doctor --fix
│
▼
Agent DB schema v19 → v21
│
▼
Session SQLite validation
│
▼
0 migration issues
│
▼
插件同步到 2026.9.5
│
▼
update status
│
▼
仍识别为标准 npm package
│
▼
update --dry-run
│
▼
未来 updater 路径验证成功
│
▼
Gateway startup
│
├── 第一次 state-lifecycle contention
│
└── systemd 自动重启
│
▼
第二次启动完成
│
▼
gateway ready
│
▼
OpenClaw 2026.9.5 可用
十八、这次升级最值得注意的几个技术点
1. “程序升级成功”和“实例升级成功”不是同一个概念
npm install success
只能证明程序包已经替换。
完整实例还必须验证:
DB Schema
Sessions
Plugins
Gateway
Agents
Updater
2. updater 失败并不意味着新版本本身无法运行
这次真正阻止标准 updater 的,是旧版本 updater 的:
database-schema-preflight
而不是 npm package 安装失败。
绕开旧 updater 后,新版自己的迁移工具反而可以成功处理数据库。
3. SQLite 是大型 Agent 实例升级中的核心组件
随着 Session 和状态数据增长,OpenClaw 已经越来越像:
一个以 SQLite 状态数据库为核心的长期运行服务
而不只是一个 Node.js CLI。
因此升级问题往往表现为:
database validation
transaction lock
schema migration
session reclamation
state lifecycle
而不是 JavaScript 文件本身。
4. 手工 npm 安装不一定破坏未来官方升级路径
只要仍然保持标准:
npm global package
结构,并且:
openclaw update status
仍然识别:
installKind = package
packageManager = npm
那么以后仍可以重新回到标准 updater。
5. systemd running 不等于应用已经 ready
对于初始化较重的服务:
systemd active
只能说明进程存活。
真正的应用健康状态应以:
socket listening
gateway ready
application status reachable
为准。
结语
这次 OpenClaw 2026.9.5 升级最终成功,但整个过程很好地展示了现代 Agent 平台升级与普通 CLI 软件更新之间的差异。
真正的升级对象已经不只是:
一个 npm package
而是一整套持续存在的运行状态:
程序
+
SQLite
+
Sessions
+
Agents
+
Plugins
+
Gateway
+
生命周期协调器
因此一个成熟的 OpenClaw 实例升级,更接近一次小型有状态服务迁移。
这次升级最终完成了:
2026.9.3
↓
2026.9.5
程序:完成
数据库:v19 → v21
Sessions:迁移检查通过
插件:同步
安装形态:保持标准 npm package
Updater:未来升级路径验证通过
Gateway:启动成功
实例:恢复正常运行
真正值得关注的并不是安装命令本身,而是程序更新之后,旧状态能否完整、安全地跨版本继续运行。