Skip to content

Conversation

@ashwin-ant
Copy link
Collaborator

Problem

ClaudeSDKClient initialization would hang indefinitely on Windows, timing out after 60 seconds. The SDK successfully spawned the Claude CLI subprocess but control requests sent via stdin never reached the subprocess due to Windows subprocess stdin buffering behavior with Python's asyncio.

Root Cause

On Windows, when using asyncio subprocess streams, data written to stdin can remain buffered and not immediately sent to the child process. The CLI subprocess waits for the initialization request that's stuck in Python's buffer, causing the 60-second timeout.

Solution

  1. Added flush_stdin() method to Transport base class (non-abstract, default no-op)
  2. Implemented Windows-specific flush in SubprocessCLITransport that calls drain() on the asyncio StreamWriter when available
  3. Call flush_stdin() after all control protocol writes in Query class:
    • After sending control requests (_send_control_request)
    • After responding to incoming requests (_handle_control_request)

Tests Added

  • test_flush_stdin_on_windows: Verifies drain() called on Windows
  • test_flush_stdin_on_non_windows: Verifies no-op on other platforms
  • test_flush_stdin_without_process: Tests graceful handling of missing process
  • test_flush_stdin_fallback_to_inner_stream: Tests wrapped stream fallback
  • test_flush_stdin_called_after_control_requests: Integration test for outgoing requests
  • test_flush_stdin_called_after_control_responses: Integration test for incoming requests

All tests pass on macOS, and the fix is platform-specific to Windows only.

🤖 Generated with Claude Code

…hangs (#208)

## Problem
ClaudeSDKClient initialization would hang indefinitely on Windows, timing out
after 60 seconds. The SDK successfully spawned the Claude CLI subprocess but
control requests sent via stdin never reached the subprocess due to Windows
subprocess stdin buffering behavior with Python's asyncio.

## Root Cause
On Windows, when using asyncio subprocess streams, data written to stdin can
remain buffered and not immediately sent to the child process. The CLI
subprocess waits for the initialization request that's stuck in Python's
buffer, causing the 60-second timeout.

## Solution
1. Added `flush_stdin()` method to Transport base class (non-abstract, default no-op)
2. Implemented Windows-specific flush in SubprocessCLITransport that calls
   `drain()` on the asyncio StreamWriter when available
3. Call `flush_stdin()` after all control protocol writes in Query class:
   - After sending control requests (_send_control_request)
   - After responding to incoming requests (_handle_control_request)

## Tests Added
- test_flush_stdin_on_windows: Verifies drain() called on Windows
- test_flush_stdin_on_non_windows: Verifies no-op on other platforms
- test_flush_stdin_without_process: Tests graceful handling of missing process
- test_flush_stdin_fallback_to_inner_stream: Tests wrapped stream fallback
- test_flush_stdin_called_after_control_requests: Integration test for outgoing requests
- test_flush_stdin_called_after_control_responses: Integration test for incoming requests

All tests pass on macOS, and the fix is platform-specific to Windows only.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant