pydantic/monty · error · ValueError
Exceeds the limit ({INT_MAX_STR_DIGITS} digits) for integer
Error message
Exceeds the limit ({INT_MAX_STR_DIGITS} digits) for integer string conversion: value has {digit_count} digits; use sys.set_int_max_str_digits() to increase the limit What it means
Monty's JSON loader (`crates/monty/src/modules/json/load.rs:340`, in `json_number_out_of_range_to_run_error`, reached via `parse_json_bytes`) enforces CPython's `sys.set_int_max_str_digits` limit (4300 digits) when a JSON number literal is a decimal integer token with too many digits. It raises Python's `ValueError` with CPython's exact message, so `json.loads('1234...')` fails identically to CPython instead of producing an arbitrarily huge int. Float/exponent tokens are exempt (they parse as float); only plain integer literals are limited.
Source
Thrown at crates/monty/src/modules/json/load.rs:340
}));
}
Ok(())
}
/// Converts `jiter`'s oversized-integer parse error into CPython's digit-limit
/// `ValueError` when the offending token is a decimal integer literal.
fn json_number_out_of_range_to_run_error(error: &JiterError, bytes: &[u8]) -> Option<RunError> {
if error.error_type != JiterErrorType::JsonError(JsonErrorType::NumberOutOfRange) {
return None;
}
let token = slice_json_number_around(bytes, error.index);
if !is_json_integer_token(token) {
return None;
}
let digit_count = decimal_digit_count_ascii(token);
check_decimal_digit_count(digit_count).err()
}
/// Returns whether a raw JSON number token is an integer literal rather than a
/// float or exponent form.
fn is_json_integer_token(token: &[u8]) -> bool {
!token.is_empty() && !token.contains(&b'.') && !token.contains(&b'e') && !token.contains(&b'E')
}
/// Returns the JSON number token that surrounds `index`.
///
/// `jiter` reports `NumberOutOfRange` at or just after the failing position, so
/// this scans outward to recover the original token for CPython-compatible
/// integer digit-limit handling.
fn slice_json_number_around(bytes: &[u8], index: usize) -> &[u8] {
let mut start = index.min(bytes.len());
while start > 0 && is_json_number_byte(bytes[start - 1]) {
start -= 1;
}View on GitHub (pinned to adc986b362)
Solutions
- In sandboxed Python code, call `sys.set_int_max_str_digits(0)` (disable) or a higher limit before `json.loads`.
- Quote the value as a JSON string (e.g. `"123456789..."`) and convert with `int(s)` semantics as needed — string keys/IDs should never be bare numbers.
- Strip leading zeros or truncate the literal in preprocessing so it stays under the digit limit.
- If the huge number is legitimate data, decode it as a float by adding `.0` or an exponent (float tokens bypass the int digit limit).
Example fix
// before
const data = JSON.parse(hugeIntJson);
// after
import sys
if hasattr(sys, 'set_int_max_str_digits'):
sys.set_int_max_str_digits(0)
data = json.loads(huge_int_json) Defensive patterns
Strategy: validation
Validate before calling
import sys
def json_safe(obj):
if isinstance(obj, str) and obj.isdigit() and len(obj) > sys.get_int_max_str_digits():
raise ValueError('integer literal exceeds int_max_str_digits; pass it as a string')
return obj
def check_json_ints(text):
import json
for m in __import__('re').finditer(r'(?<![.eE\d])\d+', text):
if len(m.group()) > (sys.get_int_max_str_digits() or 4300):
raise ValueError(f'JSON integer literal has {len(m.group())} digits') Try / catch
import sys
try:
data = json.loads(raw)
except ValueError as exc:
if 'set_int_max_str_digits' in str(exc):
sys.set_int_max_str_digits(0)
data = json.loads(raw)
else:
raise Prevention
- Serialize IDs and hashes as JSON strings, never bare numbers.
- Call sys.set_int_max_str_digits early in sandbox code that ingests third-party JSON.
- Keep integer literals in data pipelines under the 4300-digit default; check data sources for zero-padded numerics.
When it happens
Trigger: Calling `json.loads()` (or the bytes variant) on input containing an integer literal with more digits than `sys.get_int_max_str_digits()` (default 4300), e.g. a long numeric ID, key, or hash embedded as a bare JSON number.
Common situations: Parsing API responses or data dumps where 64-bit+ IDs were serialized as JSON numbers and later padded with zeros or concatenated, pushing the literal past 4300 digits; code that worked on other engines but must match CPython's int-str conversion limit.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
AI-assisted analysis of pydantic/monty@adc986b362 (2026-09-13).
Data as JSON: /api/errors/4baaaa43e7eb9118.
Report an issue: GitHub.