python/cpython · error · TypeError

Second argument to round should be integral

Error message

Second argument to round should be integral

What it means

round(Decimal, n) with a second argument requires n to be an actual int (isinstance check). Even a float with integral value like 2.0 is rejected with TypeError, because n becomes a quantize exponent (10**-n) that must be an exact integer. The one-argument form round(d) has separate NaN/Infinity handling.

Source

Thrown at Lib/_pydecimal.py:1837

        self.quantize(Decimal('1En')).

        >>> round(Decimal('123.456'), 0)
        Decimal('123')
        >>> round(Decimal('123.456'), 2)
        Decimal('123.46')
        >>> round(Decimal('123.456'), -2)
        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.

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Coerce the digit count: round(d, int(ndigits))
  2. Convert numpy integers: round(d, int(np_int))
  3. Parse config precision with int() at load time

Example fix

// before
q = round(price, ndigits)  # ndigits=2.0 from config -> TypeError

// after
q = round(price, int(ndigits))
Defensive patterns

Strategy: type-guard

Validate before calling

def is_round_ndigits(n) -> bool:
    return n is None or (isinstance(n, int) and not isinstance(n, bool))

# q = round(d, int(nd)) if nd is not None else round(d)

Type guard

def is_int_ndigits(n) -> bool:
    return isinstance(n, int) and not isinstance(n, bool)

Try / catch

try:
    q = round(d, nd)
except TypeError:
    q = round(d, int(nd))  # if nd was integral-valued float/np integer

Prevention

When it happens

Trigger: round(Decimal('1.234'), 2.0) (float -> TypeError); round(d, numpy.int64(2)) (isinstance(np.int64, int) is False on many builds); round(d, None) is fine (None means one-arg form); round(d, '2').

Common situations: Rounding precision coming from user input or config parsed as float ('round to 2.0 decimals'); numpy integers flowing into round(); decimals places computed as float division.

Related errors


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