Skip to content

Conversation

@couloirextreme
Copy link

Problem

Fixes #6 - The Claude Code SDK fails with JSONDecodeError when Claude CLI returns large responses that get split across multiple lines in the subprocess stdout stream.

This manifests as:

json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 131 (char 130)
claude_code_sdk._errors.CLIJSONDecodeError: Failed to decode JSON:
{"type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01...

Root Cause

The current implementation in SubprocessCLITransport.receive_messages() attempts to parse each line as complete JSON with json.loads(line_str), but chunked responses contain incomplete JSON fragments.

Solution

Implements a stateful JSON parser that:

  • Maintains a buffer to accumulate partial JSON across lines
  • Tracks brace/bracket nesting to identify complete JSON objects
  • Handles string escaping and quotes properly
  • Yields complete JSON objects as they're reconstructed
  • Backward compatible - no API changes

Testing

✅ Tested with real-world Linear issue analysis tool that previously caused TaskGroup errors
✅ Successfully processes large responses (4000+ chars) that were failing
✅ Maintains compatibility with simple single-line JSON responses

Before/After

Before: unhandled errors in a TaskGroup (1 sub-exception)
After: ✅ Cost: $0.4161, Duration: 97010ms, Response: [full analysis]

Fixes #6 - Handle JSON responses that are split across multiple lines
in subprocess stdout. Implements stateful JSON parser that reconstructs
complete objects from fragments.

- Maintains buffer to accumulate partial JSON across lines
- Tracks brace/bracket nesting to identify complete JSON objects
- Handles string escaping and quotes properly to avoid false boundaries
- Tested with large responses that previously caused TaskGroup errors
- Backward compatible with existing functionality

The original implementation attempted to parse each line as complete JSON
with json.loads(), but large responses get chunked across multiple lines,
causing JSONDecodeError on incomplete fragments. This fix accumulates
lines in a buffer and uses stateful parsing to extract complete JSON
objects as they become available.

Resolves 'unhandled errors in a TaskGroup' issues reported by multiple users
when processing large prompts or responses with tool usage.
Copilot AI review requested due to automatic review settings June 18, 2025 23:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the JSON parsing logic in the CLI transport to robustly handle JSON fragments spread across multiple lines.

  • Introduces a stateful JSON parser that accumulates buffer data and parses complete JSON objects
  • Replaces the per-line JSON parsing with a buffer-based approach in receive_messages

try:
data = json.loads(line_str)
# Add line to buffer
json_buffer += line_str
Copy link

Copilot AI Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying the outer 'json_buffer' inside the nested function may lead to an UnboundLocalError; consider declaring 'nonlocal json_buffer' at the start of the nested function 'read_stderr'.

Copilot uses AI. Check for mistakes.
@ltawfik
Copy link
Collaborator

ltawfik commented Jun 27, 2025

thanks @couloirextreme . This issue was already fixed in PR #5. The current implementation correctly handles multiple JSON objects.

@ltawfik ltawfik closed this Jun 27, 2025
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.

Issue with JSON parsing in SubprocessCLITransport.receive_messages

2 participants