Fix: Resolve "[Request interrupted by user]" error and improve stability
Problem Description
The API was returning "[Request interrupted by user]" error messages instead of valid responses from Claude Code. This issue occurred:
- With liteLLM integration - When using liteLLM proxy with the wrapper, requests would fail with the error message
- With certain prompt types - Some prompts (greetings, open-ended questions) triggered the SDK error more frequently
- With streaming requests - The streaming mode was particularly unstable
- With multi-turn conversations - liteLLM would re-send previous error messages in conversation history, creating a loop
Root Causes
After investigation, we identified several root causes:
-
Unstable Claude Agent SDK behavior - The SDK had unpredictable behavior with certain prompt types
- Some prompts would trigger errors with incorrect configuration
- The SDK would send error messages instead of valid responses
- No clear pattern for which prompts would fail
-
Missing system_prompt - Without explicit system_prompt, SDK behavior was unpredictable
- Different prompt types had different success rates
- liteLLM's simple greetings failed more often
-
Message parsing issues - Error messages were being treated as valid responses
-
Explicit tool disabling - Using disallowed_tools was causing SDK instability
- Better to use default SDK behavior when tools are disabled
-
liteLLM history pollution - When API returned error messages, liteLLM would include them in subsequent requests
- Created a cycle where errors kept propagating
Proposed Solutions
We should implement the following improvements:
1. Add Default System Prompt
Both streaming and non-streaming endpoints should include a default system_prompt when none is provided:
if not system_prompt:
system_prompt = "You are Claude Code, a helpful AI assistant. Answer the user's questions directly and concisely."
Impact: Improves SDK reliability for open-ended prompts and greetings.
2. Improve Message Parsing
Enhance parse_claude_message() in src/claude_cli.py to:
- Skip
SystemMessage and ResultMessage (identified by subtype field)
- Explicitly skip
UserMessage (identified by parent_tool_use_id and uuid keys)
- Only process actual
AssistantMessage content
- Filter out error messages like
"[Request interrupted by user]"
- Return empty string instead of None for better fallback handling
3. Remove Explicit Tool Disabling
Instead of using disallowed_tools when tools are disabled:
- Don't set explicit tool restrictions when
enable_tools=False
- Let the SDK use its default behavior for better stability
- Only set
allowed_tools and permission_mode when tools are explicitly enabled
4. Change Internal SDK Stream Parameter
Change the internal SDK calls from stream=True to stream=False:
- More stable and reliable for extracting complete responses
- The API still provides streaming to clients through buffering
5. Graceful Error Handling
Instead of raising HTTP 500 errors for empty responses:
- Return a placeholder message:
"I've processed your request."
- Ensures API always returns valid response objects
- Prevents cascading failures with liteLLM
6. Filter Error Messages from History
The messages_to_prompt() function should skip error messages:
- Remove
"[Request interrupted by user]" from conversation history
- Breaks the error propagation cycle with liteLLM and multi-turn conversations
Expected Outcomes
After implementing these improvements:
- ✅ "Hello!" → Valid response from Claude
- ✅ "Explain quantum computing" → Detailed explanation
- ✅ Multi-turn conversations work reliably
- ✅ liteLLM integration works seamlessly
- ✅ Streaming responses are stable
- ✅ All prompt types work consistently
Files to Modify
-
src/main.py
- Add default system_prompt in streaming endpoint (around line 603)
- Add default system_prompt in non-streaming endpoint (around line 865)
- Change stream=True to stream=False for internal SDK calls (around line 656)
- Replace HTTP 500 errors with graceful fallback messages (around lines 923 and 763)
-
src/claude_cli.py
- Enhance
parse_claude_message() function to:
- Skip messages with
subtype field (SystemMessage, ResultMessage)
- Skip UserMessage (identified by
parent_tool_use_id and uuid)
- Filter out error messages containing
"[Request interrupted by user]"
- Return empty string instead of None
-
src/message_adapter.py
- Filter error messages from conversation history in
messages_to_prompt()
- Skip messages with content
"[Request interrupted by user]"
Compatibility
- ✅ liteLLM proxy - Fully compatible
- ✅ Multi-turn conversations - Error history doesn't pollute future requests
- ✅ Streaming - Improved stability
- ✅ All prompt types - Consistent behavior
- ✅ Backward compatible - No breaking changes to API interface
Related Issues
This improvement addresses:
- liteLLM integration failures
- Unpredictable responses for certain prompt types
- Error message pollution in multi-turn conversations
- Streaming mode instability
Additional Context
The root cause analysis shows that Claude Agent SDK behavior is influenced by:
- System prompt quality and specificity
- Permission mode configuration
- Tool configuration (using default vs explicit disabling)
- Number of conversation turns in the SDK execution
These findings should inform future troubleshooting of similar issues.
Fix: Resolve "[Request interrupted by user]" error and improve stability
Problem Description
The API was returning
"[Request interrupted by user]"error messages instead of valid responses from Claude Code. This issue occurred:Root Causes
After investigation, we identified several root causes:
Unstable Claude Agent SDK behavior - The SDK had unpredictable behavior with certain prompt types
Missing system_prompt - Without explicit system_prompt, SDK behavior was unpredictable
Message parsing issues - Error messages were being treated as valid responses
Explicit tool disabling - Using
disallowed_toolswas causing SDK instabilityliteLLM history pollution - When API returned error messages, liteLLM would include them in subsequent requests
Proposed Solutions
We should implement the following improvements:
1. Add Default System Prompt
Both streaming and non-streaming endpoints should include a default system_prompt when none is provided:
Impact: Improves SDK reliability for open-ended prompts and greetings.
2. Improve Message Parsing
Enhance
parse_claude_message()insrc/claude_cli.pyto:SystemMessageandResultMessage(identified bysubtypefield)UserMessage(identified byparent_tool_use_idanduuidkeys)AssistantMessagecontent"[Request interrupted by user]"3. Remove Explicit Tool Disabling
Instead of using
disallowed_toolswhen tools are disabled:enable_tools=Falseallowed_toolsandpermission_modewhen tools are explicitly enabled4. Change Internal SDK Stream Parameter
Change the internal SDK calls from
stream=Truetostream=False:5. Graceful Error Handling
Instead of raising HTTP 500 errors for empty responses:
"I've processed your request."6. Filter Error Messages from History
The
messages_to_prompt()function should skip error messages:"[Request interrupted by user]"from conversation historyExpected Outcomes
After implementing these improvements:
Files to Modify
src/main.py
src/claude_cli.py
parse_claude_message()function to:subtypefield (SystemMessage, ResultMessage)parent_tool_use_idanduuid)"[Request interrupted by user]"src/message_adapter.py
messages_to_prompt()"[Request interrupted by user]"Compatibility
Related Issues
This improvement addresses:
Additional Context
The root cause analysis shows that Claude Agent SDK behavior is influenced by:
These findings should inform future troubleshooting of similar issues.