anthropics / anthropics/claude-code

[BUG] Regression in 2.1.228: streaming to a Bedrock gateway returns zero events, client silently falls back to non-streaming, throughput halves

オープン
#87,930 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
api:bedrock area:api bug has repro platform:windows regression stale
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code

### What's Wrong?

Starting with 2.1.228, the streaming API request from Claude Code to an
Anthropic-compatible Bedrock gateway returns a stream that closes without ever
sending a `message_start` event. The client catches this and silently retries the
request in non-streaming mode. The retry succeeds, so the session works and
nothing surfaces as an error, but two things change:

1. Wall-clock time roughly doubles. On identical ~530-token responses,
throughput goes from 53.4 tok/s to 25.9 tok/s.
2. Nothing renders incrementally. The whole reply arrives at the end.

I bisected this across five releases. 2.1.226 and 2.1.227 stream normally.
2.1.228 is the first release that fails, and 2.1.229, 2.1.233 and 2.1.235 all
fail the same way.

| build | streams natively | tok/s (warm, ~530-token response) |
|---|---|---|
| 2.1.226 | yes (`ttft_stream_ms` 1640-1774) | 53.4 (n=10, range 47.2-56.9) |
| 2.1.227 | yes (`ttft_stream_ms` 1893-5476)
| 2.1.228 | **no** | 25.0 (n=2) |
| 2.1.229 | **no** | 26.4 (n=6) |
| 2.1.235 | **no** | 25.9 (n=10) |

"Streams natively" was tested with `CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=1`,
which forbids the silent retry so the streamcall
fails outright.

Independent confirmation off the wire, using
`--output-format stream-json --include-partipt:
2.1.226 emits 150-153 `content_block_delta` events with the first arriving at
47% of the call. 2.1.228, 2.1.229 and 2.1.23s and
the response lands at 98% of the call.

The loss is not a fixed per-call cost. Holding output size fixed at four levels,
the ratio to 2.1.226 is flat: 0.51x at 4 out53x at
~2,000, 0.64x at ~6,000.

The severity here is mostly that it is silent. A visible warning would have saved
about a week of measurement on my side.

### What Should Happen?

The streaming request should succeed on 2.1.228+ as it does on 2.1.227, and
responses should render incrementally at full throughput.

Failing that, the fallback should not be silent. When the client abandons
streaming and retries in non-streaming mode, it should surface a visible warning
once per session, since the user is now paying roughly 2x wall clock with no
indication anything changed. Right now the only trace is in `--debug` output.

### Error Messages/Logs

```shell
# With CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=1, the result JSON on 2.1.228+:
"result": "API Error: Stream ended without receiving any events"
"terminal_reason": "api_error"
"is_error": true
"ttft_stream_ms": null

# From --debug --debug-file on 2.1.228, 2.1.229 and 2.1.235 (default env,
# fallback allowed) -- this is the only trace the fallback leaves:
[ERROR] Stream completed without receiving message_start event - triggering non-streaming fallback
[ERROR] Error streaming, falling back to non-streaming mode: Stream ended without receiving any events

# With the fallback disabled, the same two lines plus:
[ERROR] Error streaming (non-streaming fallback disabled): Stream ended without receiving any events
[ERROR] Error in API request: Stream ended without receiving any events

# The equivalent line on 2.1.227, which works:
[DEBUG] Stream started - received first chunk
```

### Steps to Reproduce

Requires a Bedrock deployment behind an Anthropic-compatible gateway. My env:

CLAUDE_CODE_USE_BEDROCK=1
ANTHROPIC_BEDROCK_BASE_URL=https:///v1.0/model/bedrock
ANTHROPIC_MODEL=opus[1m]

1. Download 2.1.227 and 2.1.235 as standalone binaries (I used the versioned
release bucket so I could test without installing over my working build).

2. Forbid the silent retry, so a broken streaming path fails visibly instead of
being papered over:

export CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=1

3. Ask each build for one word:

./claude227.exe -p "Reply with exactly one word: yes." --output-format json
./claude235.exe -p "Reply with exactly one word: yes." --output-format json

2.1.227 returns `"result": "yes"` with `ttft_stream_ms` around 1900.
2.1.235 returns `"is_error": true` and
`"result": "API Error: Stream ended without receiving any events"`.

4. To see it without the env var, i.e. as it actually behaves day to day, count
the streaming deltas on a response long enough to stream:

unset CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK
./claude227.exe -p "Write exactly 300 words about confidence intervals." \
--output-format stream-json --verbose --include-partial-messages \
| grep -c content_block_delta
./claude235.exe -p "Write exactly 300 words about confidence intervals." \
--output-format stream-json --verbose --include-partial-messages \
| grep -c content_block_delta

2.1.227 gives ~150. 2.1.235 gives 0. Both return the full text; only 235
takes about twice as long and delivers it all at the end.

5. Bisect if useful: 2.1.226 and 2.1.227 pass step 3, 2.1.228 onward fail.

### Claude Model

Opus

### Is this a regression?

Yes, this worked in a previous version

### Last Working Version

2.1.227

### Claude Code Version

2.1.235 (Claude Code)

### Platform

AWS Bedrock

### Operating System

Windows

### Terminal/Shell

Windows Terminal

### Additional Information

Things I ruled out by measurement, to save triage time:

- **Model.** 2.1.228 fails identically on `opus[1m]`, `claude-opus-5` and
`claude-sonnet-5`. 2.1.227 streams on all three.
- **Effort level.** 2.1.226 reads 50.3 and 53.6 tok/s at `low` against 53.4 and
55.0 at `max`. 2.1.235 reads 27.5 at `low` against 25.9 and 27.4 at `max`.
- **Extended thinking volume.** Thinking-delta characters are 0 on every
streamed call on both working builds, so there is no hidden thinking block
accounting for the extra time.
- **Request size.** Prompt totals are 22,953 / 23,008 / 23,028 tokens on
226 / 229 / 235. 2.1.235 actually sends fewer tools, 22 against 26.
- **Config toggles.** Neither `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` nor
`CLAUDE_CODE_ENABLE_FINE_GRAINED_TOOL_STREAMING=0` changes the outcome on
2.1.228 or 2.1.235.
- **Prompt caching.** Cached share of the prompt is ~100% on the failing builds,
so this is not a cache-miss effect.
- **Throttling.** Zero 429 and zero 529 across the whole window.

Possible lead, offered with low confidence: a static string scan found three
dated beta tokens present in the 2.1.228 bundle and absent from 2.1.227
(`agent-memory-2026-07-22`, `dreaming-2026-04-21`, `mcp-tunnels-2026-06-22`).
Presence in a 296 MB bundle is not evidence they are sent on the request, and
the betas toggle above did not change anything, so this may be nothing. Whatever
2.1.228 changed about the streaming request, my gateway answers 2.1.227's
version of it and not 2.1.228's. I cannot see the wire, so I cannot say which
side is at fault.

One note that may help others debugging streaming issues: `ttft_ms` in the
result JSON is not time to first token. On 2.1.226 it reads 10,384 ms on a
10.2s call and 185,898 ms on a 185.9s call, i.e. it tracks total duration even
when streaming is working normally. `ttft_stream_ms` appears to be the real
field, and it is `null` on the failing builds.

I have a repro harness (bisect with checksum-verified downloads, streaming
probe, throughput bench with a known-slow control arm) and can run any test
against 2.1.227 vs 2.1.228+ on this gateway if that helps narrow it.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Start by reproducing the regression with the Bedrock gateway, comparing 2.1.227 and 2.1.235 using CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=1 and stream-json output. Use the debug messages and event counts to trace why message_start is absent; done means streaming emits incremental events again, or the fallback shows a visible once-per-session warning.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
aws, python
領域
api, cli, cloud, performance
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
42/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。