Skip to content

fix: reasoning text trimEnd() in processor.ts invalidates Bedrock extended thinking signature #18078

Closed

Description

@wonjun3991

Bug Report

Error

undefined: The model returned the following errors:
messages.3.content.6: `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

In packages/opencode/src/session/processor.ts, the reasoning-end handler trims the reasoning text before storing it in SQLite:

case "reasoning-end":
  if (value.id in reasoningMap) {
    const part = reasoningMap[value.id]
    part.text = part.text.trimEnd()  // ← BUG: trims text permanently
    // ...
    if (value.providerMetadata) part.metadata = value.providerMetadata  // signature is for ORIGINAL text
    await Session.updatePart(part)
  }

The Amazon Bedrock API computes the signature cryptographically over the exact original bytes of the reasoning text (including trailing whitespace). When opencode calls trimEnd():

  • Stored text: "Let me think..." (trimmed)
  • Stored signature: computed over "Let me think...\n\n" (original)

On the next request, Bedrock receives text ≠ signature → ValidationException: "cannot be modified".

Data Flow

Bedrock response: reasoning.text = "thinking...\n\n", signature = "sig123"
    ↓
processor.ts reasoning-end: part.text = "thinking..." (trimEnd applied)
    ↓
SQLite: { text: "thinking...", metadata: { bedrock: { signature: "sig123" } } }
    ↓
Next request: text = "thinking...", signature = "sig123"
    ↓
Bedrock validates: sig123 was for "thinking...\n\n" ≠ "thinking..." → ERROR ❌

Fix

In packages/opencode/src/session/processor.ts, remove trimEnd() from the reasoning-end case:

case "reasoning-end":
  if (value.id in reasoningMap) {
    const part = reasoningMap[value.id]
    // REMOVED: part.text = part.text.trimEnd()
    // Reasoning text must be preserved byte-for-byte — the API-provided signature
    // validates the exact content. Trimming invalidates the signature and causes
    // "thinking blocks cannot be modified" on the next Bedrock request.
    part.time = { ...part.time, end: Date.now() }
    if (value.providerMetadata) part.metadata = value.providerMetadata
    await Session.updatePart(part)
    delete reasoningMap[value.id]
  }

Related Bug in @ai-sdk/amazon-bedrock

A secondary bug exists in packages/amazon-bedrock/src/convert-to-bedrock-chat-messages.ts where trimIfLast() is applied to reasoning blocks that have a signature:

// BUGGY (line 298):
text: trimIfLast(isLastBlock, isLastMessage, isLastContentPart, part.text),
signature: reasoningMetadata.signature,

// FIX: never trim when signature is present
text: reasoningMetadata.signature != null
  ? part.text
  : trimIfLast(isLastBlock, isLastMessage, isLastContentPart, part.text),
signature: reasoningMetadata.signature,

This should be reported separately to vercel/ai.

Reproduction

  1. Configure OpenCode with Claude Opus 4 via Amazon Bedrock (extended thinking enabled)
  2. Have a multi-turn conversation where extended thinking is used
  3. Error appears on the turn after extended thinking was used (typically turn 2-3)

Environment

  • OpenCode: v1.2.27
  • Provider: amazon-bedrock
  • Model: global.anthropic.claude-opus-4-6-v1 (variant: max)
  • Confirmed in oh-my-opencode logs: ValidationException on converse-stream

Activity

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

    @github-actions
    Contributor

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

    If #18078 is intended as the fix/root-cause clarification for #18073, please consider closing one of them or linking them explicitly.

  3. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
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