openclaw - 💡(How to fix) Fix Bug: stripInvalidThinkingSignatures modifies latest assistant message — causes Anthropic invalid_request_error

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Version: 2026.5.20
Model: anthropic/claude-sonnet-4-6 (any Claude 4.x with thinking blocks in session history)
Error:

[assistant turn failed before producing content]
LLM error invalid_request_error: messages.15.content.1: thinking or redacted_thinking 
blocks in the latest assistant message cannot be modified. These blocks must remain 
as they were in the original response.

Error Message

[assistant turn failed before producing content] LLM error invalid_request_error: messages.15.content.1: thinking or redacted_thinking blocks in the latest assistant message cannot be modified. These blocks must remain as they were in the original response.

Root Cause

stripInvalidThinkingSignatures in selection-BmjEdnnA.js iterates over ALL assistant messages including the latest one. When it strips thinking blocks from the latest assistant message (due to signature invalidation from model switching or thinking level changes mid-session), the next API call violates Anthropic's constraint: thinking blocks in the most recent assistant turn must be sent back verbatim.

Ironically, the sibling function dropThinkingBlocks in the same file already has the correct guard — it explicitly finds latestAssistantIndex and skips that message. stripInvalidThinkingSignatures is missing this same protection.

Fix Action

Fix

Apply the same latestAssistantIndex guard to stripInvalidThinkingSignatures:

function stripInvalidThinkingSignatures(messages) {
  // Find latest assistant message — never strip its thinking blocks
  let latestAssistantIndex = -1;
  for (let i = messages.length - 1; i >= 0; i -= 1)
    if (isAssistantMessageWithContent(messages[i])) { latestAssistantIndex = i; break; }

  let touched = false;
  const out = [];
  for (let i = 0; i < messages.length; i++) {
    const message = messages[i];
    if (!isAssistantMessageWithContent(message)) { out.push(message); continue; }
    if (i === latestAssistantIndex) { out.push(message); continue; }  // ← ADD THIS
    // ... rest of existing logic unchanged
  }
  return touched ? out : messages;
}

Code Example

[assistant turn failed before producing content]
LLM error invalid_request_error: messages.15.content.1: thinking or redacted_thinking 
blocks in the latest assistant message cannot be modified. These blocks must remain 
as they were in the original response.

---

// dist/selection-BmjEdnnA.js — function stripInvalidThinkingSignatures (line ~2748)
// MISSING: protection for latest assistant message
function stripInvalidThinkingSignatures(messages) {
  let touched = false;
  const out = [];
  for (const message of messages) {  // <-- iterates ALL messages including latest
    if (!isAssistantMessageWithContent(message)) { ... }
    // strips thinking blocks — including from latest assistant turn ← BUG
  }
}

---

function dropThinkingBlocks(messages) {
  let latestAssistantIndex = -1;
  for (let i = messages.length - 1; i >= 0; i -= 1)
    if (isAssistantMessageWithContent(messages[i])) { latestAssistantIndex = i; break; }
  // ... skips i === latestAssistantIndex ← CORRECT
}

---

function stripInvalidThinkingSignatures(messages) {
  // Find latest assistant message — never strip its thinking blocks
  let latestAssistantIndex = -1;
  for (let i = messages.length - 1; i >= 0; i -= 1)
    if (isAssistantMessageWithContent(messages[i])) { latestAssistantIndex = i; break; }

  let touched = false;
  const out = [];
  for (let i = 0; i < messages.length; i++) {
    const message = messages[i];
    if (!isAssistantMessageWithContent(message)) { out.push(message); continue; }
    if (i === latestAssistantIndex) { out.push(message); continue; }  // ← ADD THIS
    // ... rest of existing logic unchanged
  }
  return touched ? out : messages;
}
RAW_BUFFERClick to expand / collapse

Summary

Version: 2026.5.20
Model: anthropic/claude-sonnet-4-6 (any Claude 4.x with thinking blocks in session history)
Error:

[assistant turn failed before producing content]
LLM error invalid_request_error: messages.15.content.1: thinking or redacted_thinking 
blocks in the latest assistant message cannot be modified. These blocks must remain 
as they were in the original response.

Root Cause

stripInvalidThinkingSignatures in selection-BmjEdnnA.js iterates over ALL assistant messages including the latest one. When it strips thinking blocks from the latest assistant message (due to signature invalidation from model switching or thinking level changes mid-session), the next API call violates Anthropic's constraint: thinking blocks in the most recent assistant turn must be sent back verbatim.

Ironically, the sibling function dropThinkingBlocks in the same file already has the correct guard — it explicitly finds latestAssistantIndex and skips that message. stripInvalidThinkingSignatures is missing this same protection.

Affected Code

// dist/selection-BmjEdnnA.js — function stripInvalidThinkingSignatures (line ~2748)
// MISSING: protection for latest assistant message
function stripInvalidThinkingSignatures(messages) {
  let touched = false;
  const out = [];
  for (const message of messages) {  // <-- iterates ALL messages including latest
    if (!isAssistantMessageWithContent(message)) { ... }
    // strips thinking blocks — including from latest assistant turn ← BUG
  }
}

Compare with the correct pattern already in dropThinkingBlocks:

function dropThinkingBlocks(messages) {
  let latestAssistantIndex = -1;
  for (let i = messages.length - 1; i >= 0; i -= 1)
    if (isAssistantMessageWithContent(messages[i])) { latestAssistantIndex = i; break; }
  // ... skips i === latestAssistantIndex ← CORRECT
}

Fix

Apply the same latestAssistantIndex guard to stripInvalidThinkingSignatures:

function stripInvalidThinkingSignatures(messages) {
  // Find latest assistant message — never strip its thinking blocks
  let latestAssistantIndex = -1;
  for (let i = messages.length - 1; i >= 0; i -= 1)
    if (isAssistantMessageWithContent(messages[i])) { latestAssistantIndex = i; break; }

  let touched = false;
  const out = [];
  for (let i = 0; i < messages.length; i++) {
    const message = messages[i];
    if (!isAssistantMessageWithContent(message)) { out.push(message); continue; }
    if (i === latestAssistantIndex) { out.push(message); continue; }  // ← ADD THIS
    // ... rest of existing logic unchanged
  }
  return touched ? out : messages;
}

Reproduction

  1. Use anthropic/claude-sonnet-4-6 with thinking enabled for several turns
  2. Toggle thinkingDefault off mid-session (or switch models)
  3. Continue the session — next turn with a long history will trigger the error

Workaround (until patched)

  • /new on affected sessions (history is permanently corrupted once the error fires)
  • Avoid toggling thinkingDefault mid-session
  • We applied the above patch directly to our dist as a local hotfix

Environment

  • OpenClaw 2026.5.20
  • Claude Sonnet 4-6 via Anthropic API
  • macOS arm64

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Bug: stripInvalidThinkingSignatures modifies latest assistant message — causes Anthropic invalid_request_error