Summary
A botched update.run (npm upgrade triggered via the gateway) left
the package half-installed. The post-restart maintenance step then
tried to load a module that no longer existed at the path the new
build expected, crashed, and a live Telegram session lost its
<sessionId>.jsonl transcript. Every subsequent message to that
Telegram chat then hit claude --resume <id> against a missing
file, failed in ~400 ms, and surfaced as
"Something went wrong while processing your request" to the user.
Version
- openclaw 2026.5.2 (8b2a6e5), macOS, Node v25.9.0 via nvm
Reproduction (observed)
-
Gateway running with active Telegram session.
-
update.run initiated (npm package upgrade) by openclaw-control-ui.
-
Module resolution failed mid-restart:
[gateway] request handler failed: Error: Cannot find module
'/opt/homebrew/lib/node_modules/openclaw/dist/task-registry.maintenance-DuW0FRWY.js'
imported from .../dist/status.summary-D7d6QRTx.js
[gateway] shutdown error: ERR_MODULE_NOT_FOUND ... server-close-D1yUo6cN.js
-
After restart, every Telegram turn fails with FailoverError in
~400 ms (both Opus 4.7 and Sonnet 4.6), because the session's
transcript file no longer exists.
-
openclaw sessions cleanup --enforce --fix-missing confirmed the
record pointed at a missing transcript and pruned it.
Two underlying bugs
Bug 1 — update.run is not atomic
A failed/in-progress install leaves modules referenced by sibling
modules at hashed paths that no longer match. The gateway should
download → verify all module imports resolve → swap atomically.
Right now a partial install is reachable by the live process and
crashes the maintenance routine.
Bug 2 — session-store entries for shell-only cron jobs
systemEvent run: cron jobs (pure shell, no LLM turn) get a row in
sessions.json and a .trajectory-path.json + .trajectory.jsonl,
but never a <id>.jsonl. openclaw doctor then reports them as
"missing transcripts" forever, and cleanup --fix-missing prunes
them — but they should never have been registered as resumable
sessions in the first place. Example session ids that exhibit this:
a1287341-..., 04ab26a5-..., cb3b51f9-... (all cron-driven
systemEvent jobs).
Bug 3 (nice-to-have) — auto-recover from missing transcripts
When claude --resume <id> fails because the transcript file is
gone, the gateway loops forever on the same broken session record.
It should auto-prune the record and start a fresh session for that
sessionKey instead of failing every turn for the user.
Workaround
- Run
openclaw sessions cleanup --enforce --fix-missing
- Or schedule it daily via
openclaw cron add --system-event 'run: ...'
Logs (trimmed)
14:05:50 [gateway] request handler failed: ERR_MODULE_NOT_FOUND task-registry.maintenance
14:05:51 [gateway] shutdown error: ERR_MODULE_NOT_FOUND server-close
14:10:23 [diagnostic] stuck session: sessionKey=agent:main:telegram:direct:<redacted>
age=135s reason=queued_work_without_active_run
14:52:43 claude live session turn failed: provider=claude-cli ... durationMs=300011 error=FailoverError
15:10:22 claude live session turn failed: durationMs=384 error=FailoverError (immediate)
Summary
A botched
update.run(npm upgrade triggered via the gateway) leftthe package half-installed. The post-restart maintenance step then
tried to load a module that no longer existed at the path the new
build expected, crashed, and a live Telegram session lost its
<sessionId>.jsonltranscript. Every subsequent message to thatTelegram chat then hit
claude --resume <id>against a missingfile, failed in ~400 ms, and surfaced as
"Something went wrong while processing your request" to the user.
Version
Reproduction (observed)
Gateway running with active Telegram session.
update.runinitiated (npm package upgrade) by openclaw-control-ui.Module resolution failed mid-restart:
After restart, every Telegram turn fails with FailoverError in
~400 ms (both Opus 4.7 and Sonnet 4.6), because the session's
transcript file no longer exists.
openclaw sessions cleanup --enforce --fix-missingconfirmed therecord pointed at a missing transcript and pruned it.
Two underlying bugs
Bug 1 — update.run is not atomic
A failed/in-progress install leaves modules referenced by sibling
modules at hashed paths that no longer match. The gateway should
download → verify all module imports resolve → swap atomically.
Right now a partial install is reachable by the live process and
crashes the maintenance routine.
Bug 2 — session-store entries for shell-only cron jobs
systemEvent run:cron jobs (pure shell, no LLM turn) get a row insessions.jsonand a.trajectory-path.json+.trajectory.jsonl,but never a
<id>.jsonl.openclaw doctorthen reports them as"missing transcripts" forever, and
cleanup --fix-missingprunesthem — but they should never have been registered as resumable
sessions in the first place. Example session ids that exhibit this:
a1287341-...,04ab26a5-...,cb3b51f9-...(all cron-drivensystemEventjobs).Bug 3 (nice-to-have) — auto-recover from missing transcripts
When
claude --resume <id>fails because the transcript file isgone, the gateway loops forever on the same broken session record.
It should auto-prune the record and start a fresh session for that
sessionKey instead of failing every turn for the user.
Workaround
openclaw sessions cleanup --enforce --fix-missingopenclaw cron add --system-event 'run: ...'Logs (trimmed)