python/cpython · error · ZeroDivisionError

division by zero

Error message

division by zero

What it means

ZeroDivisionError raised by int_divmod in Lib/_pylong.py, the asymptotically fast Python implementation of divmod() for very large ints. CPython delegates divmod on huge integers to this module, and it explicitly guards the b == 0 case with this message. It is the same error you get from the built-in divmod, just thrown from the fast-path module.

Source

Thrown at Lib/_pylong.py:533

    n = b.bit_length()
    a_digits = _int2digits(a, n)

    r = 0
    q_digits = []
    for a_digit in reversed(a_digits):
        q_digit, r = _div2n1n((r << n) + a_digit, b, n)
        q_digits.append(q_digit)
    q_digits.reverse()
    q = _digits2int(q_digits, n)
    return q, r


def int_divmod(a, b):
    """Asymptotically fast replacement for divmod, for 'int'.
    Its time complexity is O(n**1.58), where n = #bits(a) + #bits(b).
    """
    if b == 0:
        raise ZeroDivisionError('division by zero')
    elif b < 0:
        q, r = int_divmod(-a, -b)
        return q, -r
    elif a < 0:
        q, r = int_divmod(~a, b)
        return ~q, b + ~r
    else:
        return _divmod_pos(a, b)


# Notes on _dec_str_to_int_inner:
#
# Stefan Pochmann worked up a str->int function that used the decimal
# module to, in effect, convert from base 10 to base 256. This is
# "unnatural", in that it requires multiplying and dividing by large
# powers of 2, which `decimal` isn't naturally suited to. But
# `decimal`'s `*` and `/` are asymptotically superior to CPython's, so
# at _some_ point it could be expected to win.

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Check the divisor before dividing: if b == 0: handle the degenerate case explicitly instead of calling divmod.
  2. If zero is a legitimate value, decide on semantics (return None, skip the item, or raise your own domain error with context).
  3. If you called _pylong.int_divmod directly, use the built-in divmod which has the same behavior but clearer provenance.

Example fix

// before
q, r = divmod(total, count)

// after
if count == 0:
    raise ValueError(f"cannot normalize: count is 0 for total={total}")
q, r = divmod(total, count)
Defensive patterns

Strategy: validation

Validate before calling

def safe_divmod(a, b):
    if b == 0:
        raise ValueError('divisor must be nonzero')
    return divmod(a, b)

Try / catch

try:
    q, r = divmod(a, b)
except ZeroDivisionError:
    q, r = 0, a  # only if zero-divisor is semantically OK in your domain

Prevention

When it happens

Trigger: divmod(a, b) (or operations like //, % that route through divmod) where b == 0 and the operands are large enough that CPython dispatches to _pylong.int_divmod instead of the C long/long path. Also reachable by directly calling _pylong.int_divmod(a, 0).

Common situations: Computing quotients with a divisor computed at runtime (counts, differences, normalization factors) that can be zero; batch/financial/bignum scripts where a denominator is an aggregation that came back empty; fuzz tests hitting _pylong directly.

Related errors


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