Skip to content

Bug: anthropic-transport-stream overwrites signature_delta instead of appending, causing permanent session corruption #87574

Description

@ploy-elison

Summary

The anthropic-transport-stream.ts (used by the embedded agent runner) overwrites thinkingSignature on each signature_delta event instead of appending to it. Since Anthropic sends the thinking block signature across multiple signature_delta streaming chunks, only the last chunk survives. The truncated signature is persisted to the session JSONL, and all subsequent replay attempts fail with:

400: messages.N.content.M: thinking or redacted_thinking blocks in the latest assistant message cannot be modified

This permanently bricks the session with no user recovery path other than /reset.

Root Cause

File: src/agents/anthropic-transport-stream.ts:1289

// BUG: overwrites instead of appending
block.thinkingSignature = delta.signature;

Correct implementation (same repo): src/llm/providers/anthropic.ts:629-634

// Correct: initializes then appends all chunks
block.thinkingSignature = block.thinkingSignature || "";
block.thinkingSignature += event.delta.signature;

Failure Mechanism

  1. Anthropic API sends the thinking block signature in N signature_delta chunks (base64 is long)
  2. Transport stream overwrites on each chunk - only last chunk survives
  3. Truncated signature stored in session JSONL
  4. Next request replays the truncated signature - Anthropic rejects it with 400
  5. Error repeats on every subsequent turn - session permanently bricked

Secondary Issue (Non-blocking follow-up)

src/agents/anthropic-transport-stream.ts:1125 does not set a display field when initializing thinking blocks, while src/llm/providers/anthropic.ts:987 sets display: "summarized".

Note: After analysis, this is a separate concern from the signature corruption bug:

  • display is a request-level parameter (params.thinking.display), not a content block field
  • The TransportContentBlock type does not include a display field
  • Its absence does not affect signature integrity or replay correctness
  • It may affect thinking behavior on newer models (Opus 4.7 / Mythos Preview) that support adaptive thinking
  • This should be tracked as a separate follow-up, not a blocker for the signature fix

Recovery for Already-Corrupted Sessions

Existing sessions with truncated signatures are handled by wrapAnthropicStreamWithRecovery (thinking.ts:482):

  1. Corrupted session replays truncated signature → Anthropic returns 400
  2. THINKING_BLOCK_ERROR_PATTERN matches the error message
  3. Recovery strips ALL thinking blocks from the message history
  4. Retry succeeds without thinking blocks → session continues normally
  5. New responses store correct signatures going forward

Users do NOT need to /reset — the recovery mechanism handles this automatically on the next request.

Real-World Observation

Observed on a production Mac Mini gateway (OpenClaw 0.6.0-dev) with claude-opus-4-6:

  • Session with thinking enabled produces assistant message with thinking blocks
  • After a few turns, every subsequent request fails with the 400 thinking block error
  • Session permanently stuck until /reset
  • Gateway logs show repeated embedded run failover decision: decision=surface_error reason=format

Related Issues

Why Existing Fixes Are Insufficient

Fix

// src/agents/anthropic-transport-stream.ts:1289
// Before:
block.thinkingSignature = delta.signature;

// After:
block.thinkingSignature = (block.thinkingSignature || "") + delta.signature;

Acceptance Criteria

  • signature_delta chunks are concatenated, not overwritten
  • Sessions with thinking enabled can survive multiple turns without 400 errors
  • Existing tests for thinking block handling pass
  • Real-scenario proof demonstrates the patched code path correctly concatenates signatures

Non-blocking Follow-up

  • Transport thinking display parameter alignment (separate from content block storage; does not affect signature integrity)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.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:auth-providerAuth, provider routing, model choice, or SecretRef resolution may break.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