Skip to content

[Bug]: Claude CLI reused session emits synthetic empty result before real response, causing OpenClaw session discard and background task cascade #99131

Description

@jwest75674

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

When a reused claude-cli session (model = oAuth authenticated against a claude subscription) with queued Claude Code task-notifications (from finished background Agent tasks) is resumed for a new user message, the CLI immediately emits a synthetic "No response requested." result (0 bytes, ~0.5-1.2s) while continuing to process the real prompt; OpenClaw classifies the 0-byte result as empty_response, logs CLI session cleared after failed reused turn, discards the session, and the real answer (produced ~2 minutes later in the same transcript) is never delivered (reproduced ≥8 times across 2026-07-01/02), with each occurrence orphaning more background tasks and queuing more notifications, making the next resume even more likely to fail (self-reinforcing cascade). Orphaned background tasks (subagents) are then killed by the system mid process.

Steps to reproduce

  1. In a claude-cli-backed session (bundled @anthropic-ai/claude-code), have the model launch one or more background Agent tasks (Claude Code's async subagents) during a turn.
  2. Let the turn finish and let at least one background task complete or fail, so a <task-notification> is queued in the Claude session.
  3. Send a new user message to the same OpenClaw session, so the gateway spawns claude -p --resume <session> (gateway log: cli exec: ... useResume=true ... reuse=reusable).
  4. Observe the gateway log: the turn returns in ~0.5-1.2s with rawLines=3 outBytes=0 outHash=e3b0c44298fc (sha256 of empty string), followed by CLI session cleared after failed reused turn: ... reason=empty_response.
  5. Observe the Claude transcript (~/.claude/projects/<project>/<session>.jsonl): a model: "<synthetic>" assistant message "No response requested." at the same second, then the queued <task-notification> and the user's message are appended, then a full real assistant answer ~2 minutes later that OpenClaw never reads.

Deterministic on this host whenever a resume lands on a session with queued task-notifications. A concurrent-resume lock theory was tested and rejected (concurrent resumes of a clean session succeed).

Expected behavior

The user's message is answered. A resume turn whose first result event merely consumed queued task-notifications should not be treated as the turn's final answer: either the backend should wait for the real result that the same process produces afterwards, or classify the synthetic "No response requested." placeholder distinctly (it is a known Claude Code synthetic message, model: "<synthetic>") and retry/keep the session, rather than clearing the session and abandoning the in-flight work. Prior sessions on the same host with the same workload answered these resumes normally when no notifications were queued.

Actual behavior

Sequence from one occurrence (2026-07-02, all times UTC, gateway log + transcript):

  • 04:00:34.601 gateway: cli exec: provider=claude-cli model=claude-fable-5 promptChars=54 trigger=user useResume=true session=present resumeSession=0e5874e4dcf6 reuse=reusable historyPrompt=present
  • 04:00:35.754 transcript: assistant message model:"<synthetic>", text "No response requested."
  • 04:00:35.864 transcript: queued <task-notification> appended; 04:00:35.886 the user's actual message appended
  • 04:00:35.871 gateway: claude live session turn: ... durationMs=1249 rawLines=3 outBytes=0 outHash=e3b0c44298fc
  • 04:00:35.875 gateway: CLI session cleared after failed reused turn: provider=claude-cli sessionKey=agent:main:dashboard:7eb4... reason=empty_response
  • 04:00:35.960 gateway: model_fallback_decision ... reason=empty_response errorPreview="CLI backend returned an empty response." attempt=1 total=1 fallbackStepFinalOutcome=chain_exhausted fallbackConfigured=false
  • 04:00:4704:02:34.357 transcript: the same CLI process continues working and writes the full real answer - never delivered; user sees a failed turn.

Background Agent tasks hosted by the discarded session die with it; their pending notifications then poison the next resume the same way. Observed ≥6 kills 2026-07-01 17:48 → 2026-07-02 04:21, plus two more on 2026-07-02 at 11:51:15 and 12:33:26 (identical signature: rawLines=3 outBytes=0 outHash=e3b0c44298fcreason=empty_response). With no fallback configured the session dies permanently (attempt=1 total=1 chain_exhausted); on a model with a fallback chain, the fallback re-runs the turn on a fresh session (losing the in-flight work but eventually replying).

Kernel OOM was ruled out: journalctl shows zero kernel/systemd-oomd kills over 7 days spanning all occurrences; the teardown is OpenClaw's own session clear.

OpenClaw version

2026.6.6 (8c802aa)

Operating system

Ubuntu (Linux 6.8.0-124-generic, x86_64)

Install method

npm global

Model

claude-cli / claude-fable-5 (also observed 2026-07-01 with claude-sonnet-5, which recovered via history-prompt fallback)

Provider / routing chain

openclaw -> claude-cli (bundled @anthropic-ai/claude-code, subscription auth) -> anthropic

Additional provider/model setup details

Sessions in question run long multi-tool turns that spawn background Agent tasks (Claude Code async subagents). No proxy/router in the path. Node v24.16.0.

Logs

# gateway log /tmp/openclaw/openclaw-2026-07-02.log (JSON fields elided)

2026-07-02T04:00:34.601Z INFO  agent/cli-backend  cli exec: provider=claude-cli model=claude-fable-5 promptChars=54 trigger=user useResume=true session=present resumeSession=0e5874e4dcf6 reuse=reusable historyPrompt=present
2026-07-02T04:00:35.871Z INFO  agent/cli-backend  claude live session turn: provider=claude-cli model=claude-fable-5 durationMs=1249 rawLines=3 outBytes=0 outHash=e3b0c44298fc
2026-07-02T04:00:35.875Z WARN  agents/agent-command  CLI session cleared after failed reused turn: provider=claude-cli sessionKey=agent:main:dashboard:7eb4ba6f-... reason=empty_response
2026-07-02T04:00:35.960Z WARN  model-fallback/decision  candidate_failed reason=empty_response errorPreview="CLI backend returned an empty response." attempt=1 total=1 fallbackStepFinalOutcome=chain_exhausted fallbackConfigured=false

# same signature repeats: 2026-07-02T04:21:09 (durationMs=551), 2026-07-02T11:51:15, 2026-07-02T12:33:26 (durationMs=601) - all rawLines=3 outBytes=0 outHash=e3b0c44298fc

# claude transcript ~/.claude/projects/.../3d508629-08aa-4709-9af1-6381d0466ce0.jsonl (same second)
2026-07-02T04:00:35.754Z assistant model=<synthetic>  "No response requested."
2026-07-02T04:00:35.864Z user  <task-notification> <task-id>a11ffd73ecce4ba31</task-id> ...
2026-07-02T04:00:35.886Z user  [Wed 2026-07-01 22:00 MDT] how are things progressing?
2026-07-02T04:02:34.357Z assistant model=claude-fable-5  (full real answer - never delivered)


Note: `resumeSession=` in the gateway log is a 12-hex sha256 truncation of the CLI session id (verified sha256("3d508629-…")[:12] = 0e5874e4dcf6), which makes correlating gateway↔transcript non-obvious during debugging.

Screenshots, recordings, and evidence

Transcript excerpt above is the primary evidence; full transcript retained locally and can be shared (redacted) on request.

Impact and severity

  • Affected: any claude-cli-backed session that uses Claude Code background Agent tasks; on this host, the main webchat/dashboard operator sessions.
  • Severity: high - the session's answer is lost, in-flight background agents are abandoned, and without a fallback chain the session is permanently dead from the user's perspective.
  • Frequency: deterministic when a resume lands on queued task-notifications; ≥8 occurrences in ~19 hours once the cascade started.
  • Consequence: self-reinforcing failure loop (killed turns orphan more tasks → more queued notifications → next resume fails), lost long-running work, and misleading triage (initially chased as OOM because the observable was "process tree gone").

Additional information

Related but distinct existing reports:

Suggested direction (from code-external observation only): treat a <synthetic>/"No response requested." 0-byte first result on a resumed session as "notifications consumed, keep reading" (the same process demonstrably continues to the real answer), or at minimum classify it as retryable-on-same-session rather than empty_response → clear.

Workaround in production here: run long background work as fully detached headless claude -p workers (setsid/nohup, results to files) so nothing rides on OpenClaw's session process tree, but this is not intuitive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingbug:behaviorIncorrect behavior without a crashclawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.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.maturity:stableIssue affects a taxonomy feature currently scored M4/M5.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions