Skip to content

Fix: Resolve '[Request interrupted by user]' error and improve stability #51

@koperic

Description

@koperic

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:

  1. With liteLLM integration - When using liteLLM proxy with the wrapper, requests would fail with the error message
  2. With certain prompt types - Some prompts (greetings, open-ended questions) triggered the SDK error more frequently
  3. With streaming requests - The streaming mode was particularly unstable
  4. 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:

  1. 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
  2. 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
  3. Message parsing issues - Error messages were being treated as valid responses

  4. Explicit tool disabling - Using disallowed_tools was causing SDK instability

    • Better to use default SDK behavior when tools are disabled
  5. 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

  1. 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)
  2. 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
  3. 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:

  1. System prompt quality and specificity
  2. Permission mode configuration
  3. Tool configuration (using default vs explicit disabling)
  4. Number of conversation turns in the SDK execution

These findings should inform future troubleshooting of similar issues.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions