#23113: fix: show actual runtime version after update/restart when service marker is stale
size: S
Cluster:
Gateway and System Fixes
## Summary
This PR fixes a version-reporting mismatch where gateway/runtime surfaces can show an old version after a successful `openclaw update` + `openclaw gateway restart`.
In real usage, the process is updated and restarted correctly, but status/presence/hello payloads can still report the previous release because `OPENCLAW_SERVICE_VERSION` is service-unit metadata and can lag behind the running binary.
## User-facing problem
After updating to a newer npm/pnpm release, users may see:
- CLI version: new (for example `2026.2.21-2`)
- Gateway process: restarted and healthy
- Reported gateway app version in status/presence: old (for example `2026.2.19-2`)
This is confusing and looks like restart failed, even when it succeeded.
## Root cause
Runtime version selection favored environment markers (especially `OPENCLAW_SERVICE_VERSION`) that are tied to installed service metadata.
That marker can be stale when:
1. package update installs newer code
2. service is restarted
3. unit metadata was not reinstalled/regenerated in the same step
Result: runtime endpoints report stale metadata instead of the actual running module version.
## What this PR changes
### 1) Add centralized runtime version resolver
- Reintroduces `resolveRuntimeServiceVersion(...)` in `src/version.ts`
- Defines explicit precedence:
1. `OPENCLAW_VERSION` (explicit override)
2. `VERSION` (actual running module build)
3. `OPENCLAW_SERVICE_VERSION` (service metadata marker)
4. `npm_package_version`
5. fallback
### 2) Use resolver in system presence
- `src/infra/system-presence.ts`
- Self-presence now reports runtime-resolved version instead of raw env fallback chain
### 3) Use resolver in gateway hello handshake
- `src/gateway/server/ws-connection/message-handler.ts`
- `hello-ok.server.version` now reports the same runtime-resolved value
## Why this approach
- Keeps support for explicit overrides (`OPENCLAW_VERSION`)
- Preserves compatibility when runtime module version is unavailable (still falls back)
- Removes misleading stale-version reporting in normal updated-service flows
- Aligns version semantics across status/presence/hello surfaces
## Tests
Updated/added tests in `src/version.test.ts`:
- prefers `OPENCLAW_VERSION` over all
- prefers runtime module version over stale service marker
- falls back to service marker, then npm package version
Local test run:
```bash
corepack pnpm vitest run --config vitest.unit.config.ts src/version.test.ts src/infra/system-presence.test.ts
```
Result: passing.
## Backward compatibility
No config/schema changes.
No behavior change for users relying on `OPENCLAW_VERSION` override.
Only improves correctness when service metadata is stale.
## Reproduction (before fix)
1. Update OpenClaw via npm/pnpm
2. Restart gateway service (`openclaw gateway restart`)
3. Check status/hello/presence
4. Observe old version still shown in some runtime surfaces
## Verification (after fix)
Same flow should now report the currently running build version consistently.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Centralizes version resolution to prefer actual running build version over stale service metadata, fixing the issue where gateway/runtime surfaces report old versions after successful updates.
**Key changes:**
- Added `resolveRuntimeServiceVersion()` with explicit precedence: `OPENCLAW_VERSION` → runtime `VERSION` → `OPENCLAW_SERVICE_VERSION` → `npm_package_version` → fallback
- Updated `system-presence.ts` to use the resolver instead of manual env fallback chain
- Updated `message-handler.ts` hello handshake to use the resolver for consistent version reporting
- Added comprehensive tests covering the precedence logic
**Issue found:**
- The runtime `VERSION` constant defaults to "0.0.0" when metadata is unavailable. The current logic will return "0.0.0" instead of falling back to `OPENCLAW_SERVICE_VERSION`, which may contain the actual version in edge cases where module version resolution fails but service metadata is available.
<h3>Confidence Score: 3/5</h3>
- Generally safe but has an edge case bug that could cause incorrect version reporting
- The PR correctly addresses the core issue of stale version reporting and adds proper test coverage. However, there's a logical bug where the fallback VERSION value "0.0.0" would be preferred over a valid `OPENCLAW_SERVICE_VERSION`. The fix is simple (exclude "0.0.0" from being considered a valid runtime version), but the bug could cause incorrect version reporting in edge cases.
- src/version.ts needs the logic fix for handling "0.0.0" fallback
<sub>Last reviewed commit: 4f8f588</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16016: fix: update systemd unit version on gateway restart
by jbold · 2026-02-14
79.6%
#23299: fix(status): show runtime model context limit instead of stale sess...
by SidQin-cyber · 2026-02-22
78.1%
#12804: fix(daemon): use wrapper script for pnpm global installs in service...
by odinho · 2026-02-09
77.4%
#19885: test(gateway,browser): isolate tests from ambient OPENCLAW_GATEWAY_...
by NewdlDewdl · 2026-02-18
76.9%
#17835: Fix misleading gateway stop hints for standalone listeners
by ConnorCallison · 2026-02-16
76.3%
#17237: fix(update): guard post-install imports after npm global update
by tdjackey · 2026-02-15
76.2%
#6064: fix(daemon): prefer bundled node from install-cli.sh over system node
by joyshmitz · 2026-02-01
76.2%
#21271: fix(commands): pass channel/capabilities/shell/os to runtime in com...
by evansantos · 2026-02-19
75.8%
#9156: fix(status): refresh version/commit on gateway restart
by gavinbmoore · 2026-02-04
75.7%
#11455: fix(gateway): default gateway.mode to local when unset
by AnonO6 · 2026-02-07
75.4%