Skip to content

Gateway update.run can leave half-installed package, killing live session transcripts #77011

Description

@ChattanoogaDan

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)

  1. Gateway running with active Telegram session.

  2. update.run initiated (npm package upgrade) by openclaw-control-ui.

  3. 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
    
  4. 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.

  5. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions