Skip to content

Desktop: reasoning_content in the thinking mode must be passed back to the API - Cline replays tool_use-only assistant turns with no reasoning block (opencode-go / deepseek-v4.1-flash) #14965

Open

Description

@erflores-tech

Environment

Cline platform Desktop App (cline-app.exe 0.0.45)
Sidecar / runtime code-sidecar.exe, bundled Bun (x86_64-pc-windows-msvc)
OS Windows 11 Home, build 26200 (10.0.26200)
Hardware Intel i7-12700KF (12C/20T), 63.8 GB RAM
Provider / model at failure opencode-go / deepseek-v4.1-flash (session started on cline-pass / cline-pass/deepseek-v4.1-flash)
Failure rate 100% reproducible on the affected session from the failing turn onward until it is abandoned

What happens

On a long, tool-heavy chat running a DeepSeek deepseek-v4.1-flash model in thinking mode, the run dies with:

The run failed: Upstream request failed: [invalid_request_error] The `reasoning_content` in the thinking mode must be passed back to the API. (request_id: c73c222e-1dbd-42d0-88ca-5ff5527d4006)

This is an upstream (model API) rejection, not a transport/hub failure. It is unrelated to the 16 MB hub-frame issue tracked separately (code=1006, see Related issues below).

The error is not transient: once the session reaches the offending state, every subsequent prompt send fails the same way.

Root cause

Cline persists assistant "thinking" turns as a {"type":"thinking","thinking":"…"} content block, but a substantial minority of assistant turns are persisted with no thinking block at all. When Cline rebuilds the conversation for the next request, it replays those reasoning-less assistant turns verbatim. A DeepSeek thinking-mode endpoint requires that the reasoning_content of each replayed assistant turn be passed back, so it rejects the entire request with invalid_request_error.

1. Cline's message format stores reasoning as a thinking block

An assistant turn that reasoned is stored like this (~/.cline/data/sessions/**/*.messages.json):

{
  "id": "msg_…",
  "role": "assistant",
  "content": [
    { "type": "thinking", "thinking": "…the model's reasoning…" },
    { "type": "text",     "text": "…visible answer…" },
    { "type": "tool_use", "id": "call_…", "name": "run_commands", "input": { … } }
  ],
  "modelInfo": { "id": "deepseek-v4.1-flash", "provider": "opencode-go", "family": "deepseek-flash" }
}

So Cline does capture reasoning when it is present — the pass-back requirement is satisfiable for these turns.

2. A large minority of assistant turns have no thinking block

In the affected session, 41 of 209 assistant turns are tool_use-only with no thinking block (the 42nd reasoning-less entry is the error message itself). These are exactly the turns the upstream is entitled to reject, because Cline hands the API an assistant message that does not carry the reasoning_content the endpoint requires.

The 41 offending turns are interleaved throughout the run, e.g. (1-based message indices):

87, 124, 147, 162, 172, 176, 183, 189, 201, 212, 214, 220, 225, 234, 240, 244,
249, 255, 258, 262, 270, 274, 276, 291, 295, 301, 307, 313, 315, 317, 326, 333,
337, 343, 348, 352, 367, 373, 387, 482, 488

A representative one (last assistant turn before the failure) is tool-call-only:

{
  "id": "msg_…",
  "role": "assistant",
  "content": [
    { "type": "tool_use", "id": "call_…", "name": "run_commands",
      "input": { "commands": ["python out\\cleanup.py"] } }
  ],
  "ts": 1791519495672,
  "modelInfo": { "id": "deepseek-v4.1-flash", "provider": "opencode-go", "family": "deepseek-flash" },
  "metrics": { "inputTokens": 103163, "outputTokens": 47, "cacheReadTokens": 100096, "cacheWriteTokens": 0 }
}

Note outputTokens: 47 with no thinking block — i.e. the assistant turn was recorded without any reasoning payload to pass back.

3. The failing request replays that turn to a strict endpoint

~/.cline/data/sessions/**/*.messages.json — the error is persisted as a display-only assistant message:

{
  "id": "error_…",
  "role": "assistant",
  "content": [
    { "type": "text",
      "text": "Upstream request failed: [invalid_request_error] The `reasoning_content` in the thinking mode must be passed back to the API. (request_id: c73c222e-1dbd-42d0-88ca-5ff5527d4006)" }
  ],
  "ts": 1791519497729,
  "metadata": { "displayOnly": true, "displayRole": "error" },
  "modelInfo": { "id": "deepseek-v4.1-flash", "provider": "opencode-go" }
}

The turn immediately before it (index 488) is the reasoning-less tool_use message shown above. Its tool results came back, Cline then issued the follow-up model call, and the upstream rejected the payload.

4. The session straddled two providers, which is why the strictness only bit late

Assistant turns in the affected session carry these modelInfo values:

provider / id Assistant turns
opencode-go / deepseek-v4.1-flash 165
cline-pass / cline-pass/deepseek-v4.1-flash 44

The session began on cline-pass, which tolerated the reasoning-less turns, then was switched to the opencode-go route for the same deepseek-v4.1-flash. The strict "must be passed back" validation applies on the opencode-go route, so the run started failing only once it was on that route.

Reproduction

  1. Start a Desktop chat on a DeepSeek thinking model (here, deepseek-v4.1-flash via the opencode-go route).
  2. Let the agent run a long tool loop so the history accumulates many assistant turns — in particular, the tool-call-only assistant turns that Cline records without a reasoning block.
  3. Send any prompt once such a reasoning-less assistant turn is in the replayed history.
  4. Observe The run failed: Upstream request failed: [invalid_request_error] The reasoning_content in the thinking mode must be passed back to the API. (request_id: …).
  5. Confirm in the session file that the assistant turn preceding the failing call is tool_use-only with no thinking block.

Candidate fault layers

The failure sits between two tolerant-vs-strict contracts, and both sides are implicated:

  • Cline side (primary, and independently fixable): Cline builds a request containing an assistant message that has no reasoning_content. Whether the reasoning was genuinely absent from the model's response or was dropped during capture/persistence, Cline is the party that must produce a request satisfying the model's contract. It currently does not reconcile the two.
  • Gateway side (secondary): the wording ("must be passed back to the API") is gateway-flavored, so the opencode-go route may simply be stricter than the model requires, or may enforce the rule across the whole replayed history rather than only where reasoning existed.

Either way, the on-disk evidence shows Cline itself emitting reasoning-less assistant turns, so this is materially a Cline-side defect regardless of the gateway.

Suggested fixes

  1. Guarantee reasoning_content on every replayed assistant turn to a thinking model. When assembling the request, ensure each assistant message maps its thinking block to reasoning_content. For turns that have none, do not silently omit the field where the endpoint requires it — backfill (e.g. an empty/placeholder value if accepted) or omit the offending turn.
  2. Self-recover on invalid_request_error. On this specific error, retry once with the reasoning-less assistant turn stripped or synthesized instead of failing the entire run and losing the turn.
  3. Fix reasoning capture at the source. The 41 reasoning-less tool_use turns show a lossy capture/persistence path; ensure reasoning that the model streamed is stored on the assistant turn it belongs to.
  4. Surface an actionable error. The current message is opaque to users and offers no recovery path; point at the offending turn / suggest switching model or starting a new task.

Workarounds (user-side)

  • Start a fresh chat rather than continuing a session that contains reasoning-less assistant turns.
  • Switch to a non-thinking model, or disable thinking / reasoning effort for the model, then re-send.
  • Avoid interrupting or switching providers mid tool-loop; a session that mixes tolerant and strict routes accumulates turns the strict route will reject.

Upstream reports (same error, other clients)

This exact error is not unique to Cline. It is a widely-hit failure of the opencode "Console Go" relay (opencode-go) when driving DeepSeek thinking models in agentic tool loops. The full gateway form of the message is:

Error from provider (Console Go): Upstream request failed: [invalid_request_error] The `reasoning_content` in the thinking mode must be passed back to the API.

Other clients already track it, and their diagnoses line up with this one:

  • anomalyco/opencode — the opencode.ai/zen/go ("Console Go") relay's own repo has a large cluster of this exact error, including open reports:
    • #48093 (open) — opencode-go / deepseek-v4-flash: continuing a long session returns 400 with opaque body — closest symptom match: after an assistant turn that made 3 tool calls, the next request (tool results → model) fails 400 and every retry fails identically.
    • #48180 (open) — Console Go relay: HTTP 400 (empty body) when request combines reasoning_content echo-back with reasoning_effort on deepseek-v4-flash.
    • #25000 (closed/completed) — DeepSeek V4 Pro via zen/go: reasoning_content inconsistency … in multi-turn tool calls — states the governing rule: DeepSeek thinking mode is all-or-nothing — once ANY assistant message in history carries reasoning_content, ALL subsequent assistant messages must too; a single tool_calls message without it rejects the whole request. This is exactly the mechanism observed here.
    • Also #48364 (closed/not_planned), #25758 ("thinking is enabled but reasoning_content is missing in assistant tool call message at index …"), #35689, #24334, #24083.
  • NousResearch/hermes-agent #106654 — fix(opencode-go): stop pairing reasoning_effort with DeepSeek reasoning_content echo-back on the Go relay. Reports that long tool-call sessions on opencode-go with deepseek-v4-flash die with HTTP 400 once history contains echo-back replays, and that the relay rejects only when both reasoning_content echo-back and a reasoning_effort value are present.
  • BerriAI/litellm #42310 — DeepSeek reasoning_content 400 in agentic loops: back-fill gated on thinking flag that OpenAI-compatible clients never send. Fails "iff the message list ends with a tool result and thinking was never explicitly enabled" — i.e. exactly the shape of the failing turn here (assistant tool_use → tool_result → next request).
  • router-for-me/EasyCLIProxyAPI Feature Request: CLI usage? #257 — opencode中使用deepseek 4.1flash 报错 reasoning_content … must be passed back — the same model and route.
  • wienans/vsc-opencode-zen-chat-provider Bug: When start new task, from an old task error writing file: #18 — Deepseek V4 Flash Free (new) - reasoning_content … must be passed back — OpenCode Zen route.
  • Same error class also seen in laurent22/joplin #16780, dbeaver/dbeaver #42134, endolith/open-interpreter cline failed to work via proxy. #215, pydantic/pydantic-ai Fix: Allow VSCode LM model switching from model picker (#8136) #8525.

Implication for this report: the failure is a gateway-contract bug shared across clients on the opencode-go / "Console Go" route, with three contributing conditions already identified upstream — (a) the all-or-nothing rule (#25000): one reasoning-less assistant turn poisons the whole replay, (b) reasoning echo-back not back-filled when the client never sends an explicit thinking flag, and (c) reasoning_effort colliding with reasoning echo-back. Cline's behavior here matches the affected client profile, so a Cline-side fix (and/or a relay-side fix) is warranted; this report should be cross-linked with the upstream trackers rather than treated as Cline-only.

Related issues (cline/cline)

Duplicate check: as of this writing there is no issue in cline/cline whose body contains this error string ("in the thinking mode must be passed back" → 0 results). The two closest PRs (#10712, #7888) are closed and about adjacent reasoning-content handling, not this failure.


Redaction note

All identifiers in this report are redacted. The raw session, provider settings, and logs also contain the reporter's account email, user_id/account_id/device_id, local filesystem username, provider API keys, and a live local hub auth token — none of which are reproduced here.

Activity

  1. linear-code commented on Oct 9, 2026

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

Metadata

Metadata

Assignees

No one assigned

    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