python/cpython · error · ValueError

cannot round a NaN

Error message

cannot round a NaN

What it means

round(Decimal('NaN')) — the one-argument form — raises ValueError('cannot round a NaN') because there is no nearest integer to a NaN. The two-argument form instead delegates to quantize, which returns NaN under signal-based semantics, so only the one-arg form raises here.

Source

Thrown at Lib/_pydecimal.py:1844

        Decimal('1E+2')
        >>> with localcontext(ExtendedContext):
        ...     round(Decimal('-Infinity'), 37)
        ...     round(Decimal('sNaN123'), 0)
        Decimal('NaN')
        Decimal('NaN123')

        """
        if n is not None:
            # two-argument form: use the equivalent quantize call
            if not isinstance(n, int):
                raise TypeError('Second argument to round should be integral')
            exp = _dec_from_triple(0, '1', -n)
            return self.quantize(exp)

        # one-argument form
        if self._is_special:
            if self.is_nan():
                raise ValueError("cannot round a NaN")
            else:
                raise OverflowError("cannot round an infinity")
        return int(self._rescale(0, ROUND_HALF_EVEN))

    def __floor__(self):
        """Return the floor of self, as an integer.

        For a finite Decimal instance self, return the greatest
        integer n such that n <= self.  If self is infinite or a NaN
        then a Python exception is raised.

        """
        if self._is_special:
            if self.is_nan():
                raise ValueError("cannot round a NaN")
            else:
                raise OverflowError("cannot round an infinity")
        return int(self._rescale(0, ROUND_FLOOR))

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Guard with value.is_nan() before rounding; render 'NaN' literally or substitute a policy value
  2. Filter non-finite values upstream of formatting code
  3. In the two-argument form round(d, n) NaN propagates instead — choose the form matching your error strategy

Example fix

// before
shown = round(v)  # ValueError when v is NaN

// after
shown = 'NaN' if v.is_nan() else round(v)
Defensive patterns

Strategy: validation

Validate before calling

def safe_round1(d):
    if d.is_nan():
        raise ValueError(f'cannot round NaN {d}')
    return round(d)

Type guard

def is_roundable(d) -> bool:
    return not d._is_special

Try / catch

try:
    n = round(d)
except ValueError:
    n = 0  # NaN policy
except OverflowError:
    raise OverflowError(f'cannot round {d}') from None

Prevention

When it happens

Trigger: round(Decimal('NaN')); round(Decimal('sNaN')); round(d) where d parsed from 'NaN' text in data.

Common situations: Display formatting that rounds values for output, hit by NaN sentinels from data feeds; round(x) used as a quick 'nearest int' on mixed-quality data.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/8881c898e394216a. Report an issue: GitHub.