python/cpython · error · ValueError

invalid literal for int() with base 10

Error message

invalid literal for int() with base 10

What it means

Raised by str_to_int in _pylong, the asymptotically fast decimal-string-to-int helper, when the regex \\s*([+-]?)([0-9_]+)\\s* does not match: the string (after the caller's rstrip/underscore handling upstream in int()) contains no digits at all or characters outside [0-9_] in the numeric part. It is the internal equivalent of the standard 'invalid literal for int() with base 10' error.

Source

Thrown at Lib/_pylong.py:407

def int_from_string(s):
    """Asymptotically fast version of PyLong_FromString(), conversion
    of a string of decimal digits into an 'int'."""
    # PyLong_FromString() has already removed leading +/-, checked for invalid
    # use of underscore characters, checked that string consists of only digits
    # and underscores, and stripped leading whitespace.  The input can still
    # contain underscores and have trailing whitespace.
    s = s.rstrip().replace('_', '')
    func = _str_to_int_inner
    if len(s) >= 2_000_000 and _decimal is not None:
        func = _dec_str_to_int_inner
    return func(s)

def str_to_int(s):
    """Asymptotically fast version of decimal string to 'int' conversion."""
    # FIXME: this doesn't support the full syntax that int() supports.
    m = re.match(r'\s*([+-]?)([0-9_]+)\s*', s)
    if not m:
        raise ValueError('invalid literal for int() with base 10')
    v = int_from_string(m.group(2))
    if m.group(1) == '-':
        v = -v
    return v


# Fast integer division, based on code from Mark Dickinson, fast_div.py
# GH-47701. Additional refinements and optimizations by Bjorn Martinsson.  The
# algorithm is due to Burnikel and Ziegler, in their paper "Fast Recursive
# Division".

_DIV_LIMIT = 4000


def _div2n1n(a, b, n):
    """Divide a 2n-bit nonnegative integer a by an n-bit positive integer
    b, using a recursive divide-and-conquer algorithm.

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Strip and check the string before int(): s = s.strip(); if not s or not s.lstrip('+-').replace('_','').isdigit(): handle the error
  2. If the value may be a float string, route through float() or decimal.Decimal instead
  3. For hex/octal/binary or prefixed literals, call int(s, 0) or int(s, 16) etc.
  4. Remove separators before parsing: s = s.replace(',', '')

Example fix

# before
value = int(line)          # line is '\n' or '3.14' -> ValueError

# after
line = line.strip()
if not line:
    return None
try:
    value = int(line)
except ValueError:
    value = int(float(line))
Defensive patterns

Strategy: validation

Validate before calling

def parse_int(s):
    s = s.strip().replace('_', '')
    if not s or not s.lstrip('+-').isdigit():
        raise ValueError(f'not an integer: {s!r}')
    return int(s)

Type guard

def is_int_string(s):
    s = s.strip().lstrip('+-')
    return s.isdigit()

Try / catch

try:
    value = int(raw)
except ValueError as e:
    if 'invalid literal' in str(e):
        raw = raw.strip().replace(',', '')
        value = int(float(raw)) if raw.lstrip('+-').replace('.','',1).isdigit() else None
    else:
        raise

Prevention

When it happens

Trigger: Internal fast-path call str_to_int(''), str_to_int('abc'), str_to_int('12.5') or '1e5' (decimal point / exponent not allowed), or strings with embedded whitespace like '1 2'. User-visible as the familiar ValueError from int('not a number').

Common situations: Parsing user input, CSV/JSON-ish data, or file contents with int() without stripping or format checks: empty strings from blank lines, floats-as-strings ('3.14'), hex with prefix ('0x1f' without base 0 or 16), thousands separators ('1,000'), or locale-formatted numbers.

Related errors


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