python/cpython · error · ValueError
cannot convert NaN to integer ratio
Error message
cannot convert NaN to integer ratio
What it means
Decimal.as_integer_ratio() returns an exact (numerator, denominator) pair for finite decimals, but NaN has no numeric value, so it raises ValueError('cannot convert NaN to integer ratio'). Infinity hits the sibling OverflowError branch instead.
Source
Thrown at Lib/_pydecimal.py:948
return DecimalTuple(self._sign, tuple(map(int, self._int)), self._exp)
def as_integer_ratio(self):
"""Express a finite Decimal instance in the form n / d.
Returns a pair (n, d) of integers. When called on an infinity
or NaN, raises OverflowError or ValueError respectively.
>>> Decimal('3.14').as_integer_ratio()
(157, 50)
>>> Decimal('-123e5').as_integer_ratio()
(-12300000, 1)
>>> Decimal('0.00').as_integer_ratio()
(0, 1)
"""
if self._is_special:
if self.is_nan():
raise ValueError("cannot convert NaN to integer ratio")
else:
raise OverflowError("cannot convert Infinity to integer ratio")
if not self:
return 0, 1
# Find n, d in lowest terms such that abs(self) == n / d;
# we'll deal with the sign later.
n = int(self._int)
if self._exp >= 0:
# self is an integer.
n, d = n * 10**self._exp, 1
else:
# Find d2, d5 such that abs(self) = n / (2**d2 * 5**d5).
d5 = -self._exp
while d5 > 0 and n % 5 == 0:
n //= 5
d5 -= 1View on GitHub (pinned to bc6749cc3b)
Solutions
- Guard with self.is_nan() / value._is_special before calling (see defense code)
- Decide a policy for NaN: skip the record, substitute 0, or propagate an explicit error to the caller
- Validate data at ingestion so NaN sentinels never reach numeric conversion code
Example fix
// before
n, d = dec.as_integer_ratio() # ValueError on NaN
// after
if dec._is_special:
raise ValueError(f'non-finite input: {dec}')
n, d = dec.as_integer_ratio() Defensive patterns
Strategy: validation
Validate before calling
def safe_ratio(d):
if d._is_special:
raise ValueError(f'non-finite decimal: {d}')
return d.as_integer_ratio() Type guard
def has_integer_ratio(d) -> bool:
return not d._is_special Try / catch
try:
n, d_ = dec.as_integer_ratio()
except ValueError:
handle_nan(dec) # NaN input path
except OverflowError:
handle_inf(dec) # Infinity input path Prevention
- Check _is_special (or is_nan()/is_infinite()) once for both special cases
- Validate decimals are finite at ingestion before exact-ratio code
- Catch ValueError and OverflowError separately if NaN vs Infinity need different handling
When it happens
Trigger: Decimal('NaN').as_integer_ratio(); Decimal('-sNaN2').as_integer_ratio() (any NaN including signaling); values read from a feed that contained a NaN sentinel before conversion.
Common situations: Converting Decimal money/quantities to Fraction for exact rational math without pre-checking for specials; float(x).as_integer_ratio()-style code ported to Decimal where NaN can persist unparsed.
Related errors
- cannot convert Infinity to integer ratio
- Cannot convert signaling NaN to float
- Cannot convert NaN to integer
- cannot round a NaN
- Invalid microsecond separator
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/073156b38001b578.
Report an issue: GitHub.