googleapis / googleapis/python-genai

ValueError from Python's int_max_str_digits limit escapes generate_content() when the model emits an oversized integer (only JSONDecodeError is guarded in _from_response)

Open
#2,542 1 comment 0 reactions 1 assignee Claimed by @Venkaiahbabuneelam View on GitHub
priority: p2 type: bug
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

**Environment**
- python-genai: 1.73.1 (bug still present in 2.7.0, see line refs below)
- Python: 3.14.3 (any Python ≥ 3.11 with the default `int_max_str_digits=4300` is affected)
- Model: `gemini-3-flash-preview`

**Description**

When `response_schema` / `response_json_schema` is set, `GenerateContentResponse._from_response` eagerly parses the response text to populate `.parsed`:

```python
# google/genai/types.py (v2.7.0, lines 8255, 8282; also 8238, 8271 for the pydantic branches)
try:
result_text = result._get_text()
if result_text is not None:
result.parsed = json.loads(result_text)
# may not be a valid json per stream response
except json.decoder.JSONDecodeError:
pass
```

`json.loads` can raise more than `JSONDecodeError`: since Python 3.11 (CVE-2020-10735 mitigation), parsing an integer literal longer than `sys.get_int_max_str_digits()` (default 4300) raises a plain `ValueError`:

```
ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 25410 digits; use sys.set_int_max_str_digits() to increase the limit
```

This is **not** a subclass of `JSONDecodeError`, so it escapes the guard and propagates out of `generate_content()` — after the API already returned HTTP 200. The caller cannot distinguish this from an SDK/transport failure, and there is no way to access the response (e.g. `.text`) because the exception is raised before the response object is returned.

**Reproduction**

We hit this in production: the model occasionally emits a degenerate/runaway integer literal in structured output (25,410 digits in our case). The application can't prevent that — it's model output. Minimal demonstration of the parsing gap:

```python
import json
try:
json.loads('{"count": ' + "1" * 5000 + "}")
except json.JSONDecodeError:
print("handled") # <- never reached
except ValueError as e:
print(f"escapes: {e}") # <- this is what propagates out of generate_content()
```

Production stack trace (python-genai 1.73.1):

```
ValueError: Exceeds the limit (4300 digits) for integer string conversion: value has 25410 digits; use sys.set_int_max_str_digits() to increase the limit
at raw_decode (json/decoder.py:361)
at decode (json/decoder.py:345)
at loads (json/__init__.py:352)
at _from_response (google/genai/types.py:8172)
at _generate_content (google/genai/models.py:4753)
at generate_content (google/genai/models.py:6276)
```

**Expected behavior**

An unparseable response body (for whatever reason) should degrade the same way a malformed-JSON response does: `.parsed` stays `None` and the caller gets the response object back, with `.text` available for its own error handling.

**Suggested fix**

`json.JSONDecodeError` is a subclass of `ValueError`, so widening the four `except json.decoder.JSONDecodeError:` clauses in `_from_response` to `except ValueError:` keeps the existing behavior and also covers the int-limit case (lines 8238, 8255, 8271, 8282 in v2.7.0).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.