Skip to content

fix: thinking block signature lost when model differs, breaking multi-turn with extended thinking #22813

Closed as not planned

Description

@bainos

Description

When using an Anthropic model with extended thinking enabled, the following error appears mid-conversation:
The model returned the following errors: messages.N.content.1: thinking or redacted_thinking blocks in the latest assistant message cannot be modified.

Root cause is in packages/opencode/src/session/message-v2.ts. When reconstructing conversation history, reasoning parts strip providerMetadata when the message was produced by a different model:

...(differentModel ? {} : { providerMetadata: part.metadata }),

This is correct for text and tool parts — it prevents provider-specific data (e.g. OpenAI itemId) from leaking into other providers. But Anthropic's thinking blocks carry a cryptographic signature inside providerMetadata. Anthropic verifies this signature on every subsequent turn. If it is missing, the block is considered modified and the request is rejected.
The fix is to always preserve providerMetadata for reasoning parts regardless of the differentModel flag.


Steps to reproduce

  1. Enable extended thinking on a Claude 3.7+ model
  2. Have a conversation long enough to accumulate thinking blocks in history, or switch models mid-session and switch back to Anthropic
  3. Continue the conversation — the error fires on any turn that replays a thinking block without its signature

OpenCode version: 1.4.6
OS: WSL
Terminal: Alacritty

Plugins

No response

OpenCode version

1.4.6

Steps to reproduce

  1. Enable extended thinking on a Claude 3.7+ model
  2. Have a conversation long enough to accumulate thinking blocks in history, or switch models mid-session and switch back to Anthropic
  3. Continue the conversation — the error fires on any turn that replays a thinking block without its signature

Screenshot and/or share link

No response

Operating System

Win 11 (WSL)

Terminal

Alacritty

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Apr 16, 2026
  2. github-actions commented on Apr 16, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

  3. added a commit that references this issue on Apr 16, 2026
    c17c025
  4. removed
    bugSomething isn't working
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  5. r00tedbrain-backup commented on May 31, 2026

    @r00tedbrain-backup

    Confirming this reproduces on the Electron desktop app v1.15.13 (macOS, arm64) — not just the CLI. Your root-cause analysis (message-v2.ts stripping providerMetadata when differentModel === true) matches the symptom exactly.

    Trigger in my setup:

    • opencode.json declares thinking for claude-opus-4-6-20250514.
    • The active session actually runs claude-opus-4-8 (variant max, thinking budgetTokens 31999) — this is the on-wire modelID recorded in the message row.
    • Config modelID ≠ wire modelID → the differentModel branch is taken → providerMetadata (carrying the signature) is dropped on every reasoning part on replay → Anthropic returns 400 on multi-turn.

    Persisted error from ~/.local/share/opencode/log/2026-05-31T210903.log:

    ERROR service=session.processor session.id=ses_1802048ecffeR3QYgxUDXuFe9t
    messageID=msg_e7fe5ad28001Oe2AhSzVeN4Z9l
    error=messages.1.content.21: `thinking` or `redacted_thinking` blocks in the
    latest assistant message cannot be modified.
      at /Applications/OpenCode.app/Contents/Resources/app.asar/out/main/chunks/node-CiOkNpBx.js:197462
      at async postToApi (.../node-CiOkNpBx.js:197390)
      at async AnthropicMessagesLanguageModel.doStream (.../node-CiOkNpBx.js:347060)
    

    Anthropic response (verbatim, from the persisted error record in SQLite):

    "statusCode": 400, "isRetryable": false
    "request_id": "req_011CbbLmSxWcMmKJUfhaBTST"
    "message": "messages.1.content.21: `thinking` or `redacted_thinking` blocks in
     the latest assistant message cannot be modified. These blocks must remain as
     they were in the original response."
    

    Environment:

    • OpenCode.app v1.15.13 (Electron, macOS arm64, app.asar 103 MB)
    • Single plugin loaded: @ex-machina/opencode-anthropic-auth@1.7.5 (audited: transform.js does not touch reasoning blocks — only system prompt and tool_use block name)
    • Provider: Anthropic OAuth (Claude Pro/Max)
    • Model: claude-opus-4-8, variant max, extended thinking enabled (31999 tokens)
    • SQLite DB at ~/.local/share/opencode/opencode.db: 850 sessions / 88,166 messages / 340,509 parts / 7.2 GB. Long-term users hit this fast.

    Hypothesis on a manual workaround (not yet tested on my end — would appreciate confirmation): explicitly declare the on-wire model (claude-opus-4-8 in my case) in opencode.json with its own variants block, so the config modelID matches the wire modelID and differentModel evaluates to false. Brittle — breaks the next time the wire model auto-bumps — so the proper fix you propose (preserve providerMetadata unconditionally on reasoning parts) is what we need.

    Happy to provide more session/log detail if useful.

  6. rekram1-node commented on May 31, 2026

    @rekram1-node
    Contributor

    The diagnosis is wrong that's not the issue, if you can send me a session where this happened I can debug it.

  7. r00tedbrain-backup commented on Jun 1, 2026

    @r00tedbrain-backup

    Apologies for the wall of text — fair feedback, won't repeat it. Removing the attached gist. Glad to see the fix is already underway.

  8. rekram1-node commented on Jun 1, 2026

    @rekram1-node
    Contributor

    Plz dont send giant ai generated things i dont have time to read it

  9. github-actions commented on Aug 2, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions