Skip to content

WhatsApp lane remains idle/embedded_run after abort_embedded_run recovery #88660

Description

@Iman-Sharif

Summary

After stuck-session recovery aborts a WhatsApp channel lane embedded_run, the session can transition to idle while still retaining stale embedded-run state and queue depth. The result is a loop where the lane appears idle/healthy at a high level, but diagnostics continue to report idle/embedded_run,q=1 and then re-emit session.stalled for active_work_without_progress.

This is related to #85251, but this issue is narrower: it is not just that an embedded run wedges before recovery; it is that recovery can complete with residual active-work/reply-operation state still attached to an idle channel session.

Environment

  • OpenClaw: 2026.5.28 (e932160)
  • OS: Debian 12 / Linux systemd user gateway
  • Channel: WhatsApp direct session
  • Runtime/profile: Codex embedded harness with tools.profile: "coding"
  • Local diagnostic mitigation in use:
"diagnostics": {
  "stuckSessionWarnMs": 60000,
  "stuckSessionAbortMs": 120000
}

WhatsApp transport itself was verified separately as healthy: direct WhatsApp send and full agent --deliver --reply-channel whatsapp --reply-account default --reply-to ... succeeded via the gateway after repairing local CLI operator.write scope. The remaining failure is the session lifecycle state after embedded-run recovery.

User-visible symptom

  • Inbound WhatsApp/app messages are accepted and queued.
  • Stuck-session recovery eventually aborts a stale embedded run instead of requiring a manual restart.
  • However, the channel can immediately remain or return to an idle/embedded_run state with queued work, causing another stall window and delayed/lost replies.
  • From an operator perspective, the gateway and WhatsApp connection look healthy while the direct session lane is not actually clean.

Observed diagnostic sequence

Sanitized stability log excerpt:

session.stalled
  outcome=processing
  reason=active_work_without_progress
  ageMs=79014
  queueDepth=2
  activeWorkKind=embedded_run

session.stalled
  outcome=processing
  ageMs=109014
  queueDepth=2
  activeWorkKind=embedded_run

session.stalled
  outcome=processing
  ageMs=139014
  queueDepth=2
  activeWorkKind=embedded_run

session.recovery.requested
  action=abort
  ageMs=139014
  queueDepth=2
  activeWorkKind=embedded_run

session.state
  outcome=idle
  reason=stuck_recovery:aborted
  queueDepth=1

session.recovery.completed
  outcome=aborted
  action=abort_embedded_run
  ageMs=139014
  queueDepth=2
  activeWorkKind=embedded_run

A later sample showed the residual/inconsistent state:

diagnostic.liveness.warning
  source=agent:main:whatsapp:direct:<redacted>(idle/embedded_run,q=1,age=60s last=embedded_run:started)

session.stalled
  outcome=idle
  reason=active_work_without_progress
  ageMs=89994
  queueDepth=1
  activeWorkKind=embedded_run

The key inconsistency is outcome=idle plus activeWorkKind=embedded_run / last=embedded_run:started / queueDepth=1 after abort_embedded_run already completed.

Expected behavior

After abort_embedded_run completes, the channel session should not be classifiable as idle/embedded_run and should not immediately emit another active_work_without_progress stall unless a new run has actually started.

More concretely:

  • The active embedded-run marker should be cleared before or atomically with transition to idle.
  • Any reply-operation/session lock associated with the aborted run should be released.
  • If queueDepth > 0 remains, the next queued item should either be explicitly resumed/drained or safely dropped/failed in a way that cannot leave stale active-work state attached to an idle session.

Suggested fix shape

  1. In the abort_embedded_run recovery path, clear the active embedded-run handle/marker and reply-operation registry entry atomically before emitting session.state outcome=idle.
  2. Reconcile queue state after abort: if the aborted item is still counted in queue depth, remove or terminally mark it; if another item remains, start it through the normal run-start path instead of leaving the session as idle with active work.
  3. Add a regression test for a channel lane where recovery completes and post-recovery diagnostics must not report idle/embedded_run.
  4. Include a reused channel session key case such as WhatsApp/Slack, not only direct openclaw agent, because direct invocations are much less likely to reproduce this stale lane state.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.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: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions