User interrupt during streaming can freeze whitespace-only text block into history, causing persistent 400 errors
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
This issue has 15 comments on GitHub. Read the full discussion on GitHub ↗