Claude Code sends empty text content blocks to Anthropic API, causing 400 errors
Description
When a hook returns a deny/block decision, Claude Code constructs the retry API request with an empty text content block. The Anthropic API rejects this with 400. Since the conversation state doesn't change between retries, this creates an infinite loop that requires Ctrl+C to break.
Evidence
The transcript sequence is:
● Ran 1 stop hook
⎿ Stop hook error: VIOLATIONS DETECTED (1 total): ...
⎿ API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
"message":"messages: text content blocks must contain non-whitespace text"}}
The hook evaluated the agent's response (found patterns in its text), returned a deny decision, and then IMMEDIATELY the API error occurs with no agent response in between. Claude Code's client is generating the empty text content block when assembling the retry request, not the model.
Error message
API Error: 400 {"type":"error","error":{"type":"invalid_request_error",
"message":"messages: text content blocks must contain non-whitespace text"}}
Expected behavior
Claude Code should not include empty/whitespace-only text content blocks in API requests when constructing retry requests after hook deny decisions.
Actual behavior
The retry request contains an empty text content block. The API rejects it. Subsequent retries produce the same malformed request, creating an infinite unrecoverable loop.
Environment
- Claude Code v2.1.31
- Observed repeatedly across multiple sessions
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗