Skip to content

Managed restart shutdown can abort active main turns without restart-recovery state #91355

Description

@ooiuuii

Summary

Managed gateway restart shutdown can abort active main-session chat runs without first marking those sessions for restart recovery. When the old Gateway process exits after the restart drain times out, the interrupted turn can be left without abortedLastRun, so startup recovery has no durable marker to resume the turn or send the existing restart-recovery feedback.

This is a restart/session-state bug, not a message-tool final-selection bug.

Real environment observed

  • Version observed: OpenClaw 2026.6.5-beta.2
  • Surface: direct chat session on a Windows-side Gateway
  • Runtime shape: main agent using the Codex runtime
  • Trigger shape: the turn invoked a Gateway restart while the same chat turn was still in flight
  • Privacy note: channel ids, account ids, local file paths, and private user content are intentionally redacted

User-visible symptom

A user asked the agent to perform a setup/diagnostic task. The first rollout reached a managed Gateway restart command and then stopped with no task_complete, no tool return, and no final user-facing conclusion. After the Gateway came back, there was no visible restart-recovery feedback for that interrupted main turn; the user had to run a second rollout to get the actual diagnostic conclusion.

Source-level repro on current main

The restart close path already drains pending replies and active chat runs before process shutdown:

// src/gateway/server-close.ts
drainRestartPendingRepliesForShutdown(...)
// on drain timeout:
abortActiveRunsForRestart(params)

That abort path emits stopReason: "restart" and clears active chat-run state, but the close handler does not persist a restart-recovery marker for the active main session before aborting. In contrast, other restart paths already call markRestartAbortedMainSessions(...) for active embedded/main sessions before forced restart or restart-drain timeout.

A focused source-level regression for the missing behavior is:

  1. create a createGatewayCloseHandler with an active chatAbortControllers entry for a main session;
  2. call close({ reason: "gateway restarting", restartExpectedMs: 123, drainTimeoutMs: 0 }) so restart drain immediately times out;
  3. observe that the active run is aborted for restart;
  4. expected: the active main session refs are passed to a restart-recovery marker before abort;
  5. current main: there is no marker callback/bridge in the close path, so the session is aborted without durable restart-recovery state.

Expected behavior

When restart shutdown cannot drain active main-session chat runs and is about to abort them:

  • collect the active run session keys/session ids;
  • persist abortedLastRun through the existing main-session restart-recovery marker;
  • do this before aborting/clearing the active chat-run state;
  • keep normal shutdown behavior unchanged;
  • keep subagent/cron/ACP exclusion policy in the existing marker implementation.

Actual behavior

The restart close path can abort active chat runs with stopReason: "restart" without persisting abortedLastRun for the affected main session. On the next Gateway startup, restart recovery may have no marker to resume the interrupted turn or emit the existing unresumable-session notice.

Scope / non-goals

Proposed fix

Add a narrow bridge from the Gateway close/restart-drain path to markRestartAbortedMainSessions(...). On restart-drain timeout, mark the active main-session refs before aborting active chat runs. Keep the marker best-effort so shutdown can continue if persistence fails, but record a shutdown warning for observability.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions