User interrupt during streaming can freeze whitespace-only text block into history, causing persistent 400 errors
Status Fixed / completed
Reported on v2.1.31
Maintainer reply None cached
Workaround ✓ Mentioned in thread ↓
Activity 15 comments · opened Feb 4, 2026 · closed Apr 2, 2026
Summary
When a user interrupts a streaming response at just the right moment — before any real content is emitted — a whitespace-only text block (\n\n) gets frozen into the conversation history. All subsequent API calls then fail with:
400 {"type":"error","error":{"type":"invalid_request_error","message":"messages: text content blocks must contain non-whitespace text"}}
The session becomes unrecoverable.
Reproduction Steps
- Start a new Claude Code session
- Paste this prompt:
You are going to help me reproduce a Claude Code bug. You will guide me through each step interactively — tell me exactly what to do and when.
Here's the plan (for your reference, don't dump this all on me at once):
The bug: When a user interrupts a streaming response at just the right moment, a whitespace-only text block ("\n\n") gets frozen into the conversation history.
The API then rejects all subsequent requests with: 400 "messages: text content blocks must contain non-whitespace text"
The reproduction sequence:
1. You will call AskUserQuestion with a simple question
2. I will reject/cancel it (you'll tell me how)
3. I will immediately send a new message
4. I will interrupt your response as fast as possible
5. I will send another message — if the bug reproduced, you'll get a 400 error
Step-by-step execution:
STEP 1: Tell me "Get ready. When you see the question prompt appear, press Escape immediately to dismiss it. Then as fast as you can, type the word 'hello' and press Enter." Then call AskUserQuestion with a simple question like "What is your favorite color?" with options Red, Blue, Green.
STEP 2: After I reject the question and send "hello" (or whatever I type), you will start responding. But BEFORE you respond with any real content, tell me nothing — just start your response normally. I need to interrupt you during this moment. So actually, right after step 1, add this instruction: "After you press Enter on your message, IMMEDIATELY press Escape again before I finish responding."
So the full user instruction in step 1 should be:
"Get ready. When the question prompt appears: (1) Press Escape to dismiss it, (2) Type 'hello' and press Enter as fast as you can, (3) IMMEDIATELY press Escape again before my response finishes. You need to be very fast — press Escape within the first second of my response appearing. Then type 'test' and press Enter."
STEP 3: If my response after "test" works normally, the bug didn't reproduce. Tell me "Bug did not reproduce. Let's try again." and go back to step 1. If you get an API error, the bug reproduced — tell me what error you see.
Repeat up to 5 attempts. The timing is tight so it may take a few tries.
Start now with Step 1.
- Follow the agent's instructions. The key sequence is: Escape (dismiss question) → type "hello" + Enter → Escape (interrupt response) → type "test" + Enter
- May take 2-3 attempts due to timing sensitivity
- On success, you'll see the 400 error after sending "test"
Reproduction Session
Full session JSONL from a successful reproduction (32KB): https://gist.github.com/kitaekatt/6881749202eea47fc54e506621378e78
Root Cause
When the user interrupts a streaming response, the client saves whatever has been emitted so far into the conversation history. During the first few tokens of streaming, the model often emits \n\n before real content. If the user interrupts during this window:
- The assistant message is saved with content containing only
\n\n(whitespace-only) stop_reasonisnull(interrupted, not completed)- This message is included in all subsequent API requests
- The API rejects it because text content blocks must contain non-whitespace text
- The session is permanently broken
Suggested Fix
Before sending messages to the API, the client should sanitize the conversation history:
- Strip or remove text content blocks that contain only whitespace
- Or replace whitespace-only interrupted responses with a placeholder like
[Response interrupted] - Or validate text content blocks against the API constraint before sending
Environment
- Claude Code version: 2.1.31
- Platform: Linux (Ubuntu)
- Model: claude-opus-4-5-20251101 (but likely affects all models)
- Request ID from repro:
req_011CXoQWo3Da9HsdHkVBeRxY
15 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
This bug should be retained as it has a repo-case and full session data on a problematic session.
Claude-code is completely unusable with this happening every 10 minutes. Every time it (stupidly) runs a command that can never finish. I can't interrupt it without getting a wall of this error then breaking the entire session.
Getting the same problem constantly.
Claude Code v2.1.31 Opus 4.5
Same issue here on macOS, Claude Code v2.1.31 with claude-opus-4-5-20251101.
This has been corrupting sessions persistently. The whitespace-only text blocks (
"\n\n") get frozen into the JSONL history, making--resumefail with the same 400 error.Workaround I've been using:
SessionEndhook that cleans the JSONL on exit — removes lines where ALL content blocks are whitespace-only textfix-all-sessions.py) that scans and repairs all session files across projectsThe hook helps for clean exits, but if the session crashes or is killed (which is exactly when the whitespace blocks are most likely to be created), the hook doesn't fire and the session stays corrupted.
A client-side fix (sanitizing content blocks before sending to the API) would be much more reliable than relying on external cleanup scripts. The suggested fix in the issue description is spot-on.
According to the v2.1.33 changelog, this should now be fixed:
This matches the exact root cause described in this issue. The fix is in the normalization layer so whitespace-only text blocks are now properly handled before being sent to the API.
For anyone who implemented workarounds (like transcript sanitization hooks), you should be able to safely disable them after updating to v2.1.33.
Disclosure: the comments from this account on this issue are posted by Claude Code (Opus 4.6) on behalf of the user, as part of a learning/documentation workflow.
Thanks @samcod3 I will close this when I verify the fix
This is NOT fixed.
I'm on version v2.1.45 on macos and just had this exact problem...
Interesting I haven't had it in a while @Thinkscape can you post more details I was going to close this
I am experiencing this issue on version v2.1.56 with Claude Opus 4.6.
opus 4.6, claude code 2.1.45, macos
I have inspected it and it did have
text: ""andtext: "\n\n"messages.I unblocked myself with this script: https://gist.github.com/Thinkscape/bd30c6a17aafb2d810256c471236e807
Example messages:
Still reproducing on v2.1.77 (macOS, Opus 4.6 1M context).
The v2.1.33 fix (whitespace text + thinking block normalization) did not cover all edge cases. Whitespace-only text blocks (
text: ""andtext: "\n\n") withstop_reason: nullstill get frozen into conversation history after user interrupts during streaming.Our workaround (a
SessionEndhook that strips JSONL lines where ALL content blocks are whitespace-only) has been running continuously since Feb 5 and still catches corrupted entries on recent versions.Suggesting this issue be re-opened — the root cause (client not sanitizing whitespace-only text blocks before persisting to transcript) remains unfixed.
I'm still getting this when sending prompts to copilot and the Auto agent selects Claude Haiku to handle the response.
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.