Skip to content

fix: repair malformed JSON in streaming tool call arguments - #54

Merged
mateo-di merged 2 commits into
carto/mainfrom
bug/sc-522840/intermittent-json-parse-errors-in-responses
Dec 11, 2025
Merged

fix: repair malformed JSON in streaming tool call arguments#54
mateo-di merged 2 commits into
carto/mainfrom
bug/sc-522840/intermittent-json-parse-errors-in-responses

Conversation

@mateo-di

@mateo-di mateo-di commented Dec 5, 2025

Copy link
Copy Markdown
Collaborator

Description

Shortcut

  • Autolink: [sc-522840]

Fixes intermittent JSON parse errors in Responses API streaming with tool calls when using Gemini models.

Problem

The error manifests as:

Error: Unexpected non-whitespace character after JSON at position 95
Error: Unexpected non-whitespace character after JSON at position 60

Root cause: Gemini streaming can send duplicate/overlapping JSON chunks that when naively joined with "".join() produce malformed JSON like:

{"address":"School"}{"address":"School"}

Solution

Use Python's built-in JSONDecoder.raw_decode() to extract the first valid JSON object. This is the canonical, C-optimized O(n) solution for handling "extraneous data at the end" of JSON strings.

Reference: Python JSON Documentation

Changes

  • Add _validate_and_repair_tool_arguments() function using raw_decode()
  • Apply fix to get_combined_tool_content() and get_combined_function_call_content()
  • Add 19 comprehensive unit tests covering:
    • Valid JSON (simple, nested, arrays, escaped quotes, unicode)
    • Malformed JSON (duplicates, concatenated, garbage suffix)
    • Edge cases (empty string, empty object, invalid JSON)
    • Long/complex JSON (100 keys, 10-level nesting, 1000-element array)
    • Gemini-specific patterns (geocode duplicate, braces in strings)

Type of change

  • Fix

Acceptance

  1. Deploy to a test environment with Gemini models
  2. Test streaming + function calling with the geocoding tool
  3. Verify no more "Unexpected non-whitespace character after JSON" errors
  4. Run unit tests: pytest tests/test_litellm/litellm_core_utils/test_streaming_chunk_builder_utils.py -v

Basic checklist

  • Good PR name
  • Shortcut link
  • Just one issue per PR
  • GitHub labels
  • Proper status & reviewers
  • Tests
  • Documentation (inline code comments)

Fixes intermittent JSON parse errors in Responses API streaming with
tool calls when using Gemini models. The error manifests as:
"Unexpected non-whitespace character after JSON at position X"

Root cause: Gemini streaming can send duplicate/overlapping JSON chunks
that when naively joined with "".join() produce malformed JSON like:
'{"address":"School"}{"address":"School"}'

Solution: Use Python's built-in JSONDecoder.raw_decode() to extract
the first valid JSON object. This is the canonical, C-optimized O(n)
solution for handling "extraneous data at the end" of JSON strings.

Changes:
- Add _validate_and_repair_tool_arguments() using raw_decode()
- Apply fix to get_combined_tool_content() and get_combined_function_call_content()
- Add 19 comprehensive unit tests covering valid, malformed, edge cases

Shortcut: sc-522840
@mateo-di
mateo-di force-pushed the bug/sc-522840/intermittent-json-parse-errors-in-responses branch from d4d204c to 4306a4b Compare December 5, 2025 17:41
@mateo-di
mateo-di marked this pull request as ready for review December 11, 2025 18:58
@mateo-di
mateo-di merged commit 785d561 into carto/main Dec 11, 2025
5 of 6 checks passed
Cartofante pushed a commit that referenced this pull request Feb 4, 2026
Features restored:
- [PR #70] Azure URL suffix stripping - Strip operation suffixes
  (/chat/completions, /embeddings, etc.) from deployment URLs to
  prevent 404 errors when Azure SDK appends them again
- [PR #54] JSON repair for streaming tool calls - Use JSONDecoder.raw_decode()
  to handle malformed JSON from Gemini streaming that sends
  duplicate/overlapping chunks

Integration approach:
- PR #70: Restored regex-based stripping in select_azure_base_url_or_endpoint()
  with docstring explaining the fix. Added 12 unit tests.
- PR #54: Restored _validate_and_repair_tool_arguments() function and integrated
  it into get_combined_tool_content() and get_combined_function_call_content().
  Added 19 unit tests.

Verified: syntax checks, ruff linting passed

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mateo-di added a commit that referenced this pull request Feb 10, 2026
Static registry of critical CARTO customizations that must survive
upstream syncs. The resolver should verify all patterns exist after
every sync to prevent silent feature regressions (like the OCI Gemini
and Snowflake tool calling drops in v1.81.0).

Tracks: OCI Gemini (#68), Snowflake streaming/tool calling (#38, #58),
Azure URL stripping (#70), JSON repair (#54), Redis sessions (#16).
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