[Bug] Anthropic API Error: Opus 4.8 returns thinking-only responses without tool_use or text blocks

Open 💬 0 comments Opened Jun 15, 2026 by IWriteCuteBUG

Bug Description
Bug: Opus 4.8 returns thinking-only responses (no text/tool_use) — a second failure mode of the same regression
described in issue #68529

> Related issue: https://github.com/anthropics/claude-code/issues/68529 (2026-06-15) describes fingerprint A on
Opus 4.8: stop_reason=stop_sequence + empty/minimal output_tokens. This report describes fingerprint B:
stop_reason=tool_use|end_turn + 800–1400 output_tokens + content blocks contain only thinking (no text, no
tool_use). Both fingerprints are observed on Opus 4.8 on 2026-06-15, both produce the same client-side malformed
and could not be parsed
symptom, and both vanish on switching to Opus 4.7. They appear to be two failure modes of one
underlying regression in 4.8's tool-call / extended-thinking interaction layer.

## Symptom
Claude Code session abruptly halts with Your tool call was malformed and could not be parsed. Please retry. followed
by a second identical failure on retry, then the session stops. Reproducible across multiple sessions over the past 2
weeks on Opus 4.8 specifically.

## Root cause (confirmed from session jsonl, not speculation)
Some Opus 4.8 responses return content blocks that contain only a thinking block — no text, no tool_use. The
client cannot parse this as a valid tool call and surfaces the malformed-parse error. The response still has high
output_tokens (800–1400) and a normal stop_reason (tool_use or end_turn), so this is NOT max_tokens
truncation.

This is distinct from the fingerprint described in #68529 (where the response is essentially empty with
stop_reason=stop_sequence). The two fingerprints coexist on Opus 4.8 on the same day.

## Evidence (single session, 2026-06-15)
Running the detection script (below) on one session jsonl that contains both Opus 4.8 and Opus 4.7 responses:

```
total assistant messages = 42
orphan thinking-only messages = 4

msg_01BhXU4bG6YAoGQFQXTxU41L model=claude-opus-4-8 tokens=[REDACTED]
msg_01H6eLGmwCcc2UpDoFxeYBAA model=claude-opus-4-8 tokens=[REDACTED]
msg_01JPee8nTi9V7THbfkiD7pTH model=claude-opus-4-8 tokens=[REDACTED]
msg_01NbniykjTW7T6yHPqP8JLpu model=claude-opus-4-8 tokens=[REDACTED]
```

Key facts from the same session:

  • All 4 orphans are on claude-opus-4-8. Zero orphans on claude-opus-4-7.
  • The 3rd orphan (1270 tokens) was immediately followed by the client-side malformed and could not be parsed retry

prompt; the 4th orphan (1357 tokens) is that retry — same model again returned thinking-only.

  • After switching to /model claude-opus-4-7[1m] mid-session, every subsequent response on 4.7 contained text

and/or tool_use as expected — no orphans.

  • A concurrent session on the same machine, running entirely on Opus 4.7, produced 0 orphans across all responses.

This rules out network, proxy, payload-size, language, and effort-tier factors.

  • stop_reason distribution across the full session contains only tool_use / end_turn. **No max_tokens at

all.** Maximum output_tokens observed was ~3600 — nowhere near any output ceiling.

  • This particular jsonl happened not to contain a fingerprint-A occurrence. Per #68529, fingerprint A is still

reproducing on 2026-06-15 — both fingerprints coexist; A has NOT been fixed.

## Repro environment

  • Claude Code CLI on WSL2 (Ubuntu), Windows host
  • Model: claude-opus-4-8[1m] (1M context tier)
  • Effort: high (also seen on default; effort tier appears irrelevant)
  • Context length when the orphans occurred: ~50–100k tokens
  • Extended thinking: enabled (all observed orphans contain a non-empty thinking block; not yet tested with extended

thinking disabled — worth investigating since the failure terminates exactly at the end of the thinking block)

  • Multiple MCP tools active during the session — orphans are not correlated with any specific tool call

## Detection script
Aggregates assistant messages by message.id and flags any whose content contains a thinking block but no text
and no tool_use. This is specifically the detector for fingerprint B; the detector for fingerprint A (looking for
stop_reason=stop_sequence + zero/minimal output_tokens) is described in #68529:

```python
import json
from collections import defaultdict

path = '<session>.jsonl' # path to a Claude Code session jsonl

by_id = defaultdict(lambda: {'kinds': [], 'model': '?', 'tokens': [REDACTED]})
for line in open(path, encoding='utf-8', errors='replace'):
try: o = json.loads(line)
except: continue
if o.get('type') != 'assistant': continue
m = o.get('message', {})
mid = m.get('id')
if not mid: continue

Note: Content was truncated.

View original on GitHub ↗