Skip to content

Heartbeat fallback can deliver repeated internal stream-error placeholders #97357

Description

@Suidge

Describe the Bug

An agent heartbeat poll can send a visible Feishu DM containing many repetitions of the internal stream-error placeholder:

[assistant turn failed before producing content]

In the observed case, the heartbeat did not actually complete its configured check. Instead, after the primary model failed and the fallback model was selected, the fallback model returned a final visible message made only of repeated placeholder strings.

Steps to Reproduce

  1. Configure an agent heartbeat that should run a deterministic check and normally reply HEARTBEAT_OK.
  2. Use a primary model that can fail before producing content, for example due to provider quota/rate limit.
  3. Configure a fallback model, in this case deepseek/deepseek-v4-flash.
  4. Let the heartbeat poll fire in an existing agent session whose transcript contains previous internal placeholder/error entries.
  5. Observe that the fallback model can emit the placeholder text as the final assistant reply, and the messaging channel delivers it visibly.

Evidence

OpenClaw version:

OpenClaw 2026.6.10 (aa69b12)

Observed local session:

/Users/neoshi/.openclaw/agents/silvermoon/sessions/347f23b3-b12d-423c-a7f8-a8d04c018117.jsonl

Timeline:

2026-06-28 11:43:49 CST
role=user
content=[OpenClaw heartbeat poll]

2026-06-28 11:43:50 CST
role=assistant
provider=volcengine-plan
model=deepseek-v4-flash
stopReason=error
errorCode=AccountQuotaExceeded
text=[assistant turn failed before producing content]

2026-06-28 11:43:54 CST
role=assistant
provider=deepseek
model=deepseek-v4-flash
stopReason=stop
text_len=2064
placeholder_count=43
text=[assistant turn failed before producing content]... repeated

The fallback turn ended with stopReason=stop, so the bad placeholder text was treated as a normal final assistant response and delivered to the Feishu default bot DM.

I also checked the runtime stores around 11:35-11:50 CST:

cron_run_logs: no entries
delivery_queue_entries: no entries
task_runs: only context_engine_turn_maintenance rows, all succeeded

So this was not a cron job delivery and not a queued task failure. It was the heartbeat session itself producing a visible reply.

Expected Behavior

Heartbeat should either:

  • complete the heartbeat check and reply HEARTBEAT_OK, or
  • fail silently / emit a clear non-user-visible diagnostic, depending on heartbeat delivery policy.

Internal stream-error placeholder text should never be delivered as user-visible heartbeat output.

Actual Behavior

The heartbeat fallback model produced a visible final reply containing 43 repetitions of [assistant turn failed before producing content].

The configured heartbeat check did not run to completion. In this case scripts/heartbeat_check.py was not called.

Why This Matters

This creates a noisy direct message blast to the user and makes heartbeat status ambiguous:

  • the runtime sees a completed assistant turn,
  • the user sees repeated internal error placeholders,
  • the actual heartbeat check did not complete.

Related Issues

This is related to but distinct from:

This report is specifically about heartbeat + fallback + visible channel delivery: a fallback model echoes internal placeholder text as a normal final reply, and the heartbeat output filter does not suppress it.

Possible Fix Direction

  • Strip or suppress [assistant turn failed before producing content] from visible heartbeat replies even when returned by a fallback model as normal text.
  • Treat a heartbeat final response containing only internal placeholder text as failed/empty, not deliverable.
  • Consider isolating heartbeat prompts from prior transcript artifacts or forcing heartbeat through a deterministic tool/script response path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.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.no-staleExclude from stale automation

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions