pythonseverity: can-fix
ValueError

Python ValueError: invalid literal for int() with base 10

ValueError: invalid literal - cannot convert value

96% fixable~5 mindifficulty: beginner

Verified against CPython 3.13 source (Objects/longobject.c), Python docs: built-in-exceptions, Python docs: built-in-functions (int) · Updated April 2026

> quick_fix

A function got an argument of the right type but with a value it can't process. Most common: int('abc') - str is the right type for int() but 'abc' isn't parseable. Validate input before conversion, or wrap in try-except ValueError to handle malformed values.

# Raises ValueError
age = int('twenty')

# Fix 1 - validate first
text = 'twenty'
if text.isdigit():
    age = int(text)
else:
    age = 0

# Fix 2 - try-except
try:
    age = int(text)
except ValueError:
    age = 0

# Fix 3 - regex parse for complex inputs
import re
m = re.match(r'^\d+$', text)
age = int(m.group()) if m else 0

What causes this error

ValueError indicates the type is correct but the value is invalid for the operation. Different from TypeError (type itself wrong). Common contexts: int(), float(), datetime.strptime(), JSON parsing of malformed data, struct.unpack on wrong-sized buffer, or any function that validates value semantics after accepting the type.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Read the full error message

    ValueError: invalid literal for int() with base 10: 'twenty' - shows the function (int), the base, and the actual offending value.

  2. 02

    step 2

    Identify the source of the bad value

    It's almost always external input: a CSV column, a form field, a JSON value, an environment variable. Trace the value back to where it entered your code.

  3. 03

    step 3

    Validate before converting

    Use str.isdigit() for non-negative integers, regex for more flexibility, or try-except ValueError for general parsing.

  4. 04

    step 4

    For datetime.strptime, match the format

    datetime.strptime('2026/01/01', '%Y-%m-%d') raises - the separator is /, not -. Use a flexible parser like dateutil or normalise input first.

    from datetime import datetime
    try:
        dt = datetime.strptime(value, '%Y-%m-%d')
    except ValueError:
        dt = None
  5. 05

    step 5

    For numeric overflow, use Decimal or check ranges

    int() handles arbitrary precision but float() does not - float('1e500') raises OverflowError, but float('not_a_number') raises ValueError. Check input ranges if the source can have huge values.

How to verify the fix

  • ValueError no longer fires on the offending value.
  • Malformed input case handled with a clear default or error.
  • Edge cases (empty string, whitespace, leading zeros) handled.

Why ValueError happens at the runtime level

ValueError originates from PyExc_ValueError defined in Objects/exceptions.c. It's raised by C-level functions when they receive a parameter of the right type but with content that can't be processed. For int(s), the parser in Objects/longobject.c (long_from_string) walks the string, validating each character against the digit set for the chosen base; on the first invalid character, it sets a ValueError with a 'invalid literal for int()' message. For datetime.strptime, the format-string parser raises when the input doesn't match the format. The contract is: types are checked first via tp_check_args, values are checked second via parser-specific logic.

Common debug mistakes for ValueError

  • Calling int() on a string with leading/trailing whitespace expecting it to fail - actually int() strips whitespace by default, so int(' 42 ') works; but int('42abc') raises.
  • Using str.isnumeric() instead of isdigit() for int parsing - isnumeric matches Unicode numeric characters that int() can't parse (Roman numerals, fractions), giving false positives.
  • Catching ValueError without distinguishing from KeyError or IndexError - bundling all input-validation errors loses information needed to give a useful error message to the user.
  • Using float(s) for monetary values without checking - floats can't represent 0.1 exactly, and ValueError catches malformed input but not precision loss; use Decimal for money.
  • Calling json.loads on a config file without try-except - any malformed JSON raises ValueError (json.JSONDecodeError is a subclass), and the default error message doesn't show the offending byte position clearly.

When ValueError signals a deeper problem

Persistent ValueError at runtime usually means input validation is happening at the wrong layer. When validation lives inside business logic (deep in a function that does both parsing and computation), every malformed input bubbles up as ValueError with a stack trace that hides the entry point. The architectural fix is a typed boundary library at the input edge - Pydantic v2 for HTTP requests, attrs converters for internal data, dataclass __post_init__ for simple models. These convert raw strings to typed values once, with clear errors at the source. Internal code then operates on validated types, so ValueError becomes impossible by construction.

Editor's take

This error tends to surface at the worst possible moment in ETL pipelines — specifically during the first production run after a data source quietly changes its schema. A small startup running a nightly Django management command to ingest CSV exports from a third-party API will hit this at 2am when the vendor silently starts sending empty strings or locale-formatted numbers like '1,234' instead of '1234'. The on-call engineer, who didn't write the ingestion code, spends 40 minutes adding print statements before realizing int() was never guarded against non-numeric strings upstream.

For career stage, this is a split signal. Hitting it is pure beginner territory — but how you fix it separates levels. A junior dev wraps it in a bare except and moves on. A mid-level engineer adds a try/except ValueError with a fallback and calls it done. The engineer who's actually leveling up asks why the untrusted string reached int() at all, then pushes validation to the boundary layer using Pydantic v2's model_validator or FastAPI's request schema — so the conversion never happens on raw input. That architectural instinct is what distinguishes someone writing defensive code from someone writing correct code.

In the same incident, you'll almost always find TypeError nearby — often because the None returned from a failed int() attempt flows into arithmetic downstream. AttributeError on NoneType follows the same pattern. If the data comes from an external API, a KeyError on the dict access that fed the bad string is usually a few frames up the traceback. Together they form the classic parse-then-compute failure chain: bad input, silent None propagation, crash at the operation that assumed a clean integer.

By Bikram Nath · Curator · Updated April 2026

Frequently asked questions

Why isn't 'twenty' parseable but '20' is?

int() with base 10 only parses ASCII digits 0-9 and an optional leading + or -. Word forms ('twenty') need a different parser like word2number library.

What's the difference between ValueError and TypeError?

TypeError - the type is wrong (passing a list to int()). ValueError - the type is right but the value can't be processed (passing 'abc' to int()).

Should I catch ValueError or check first?

Pythonic style is EAFP (easier to ask forgiveness than permission) - try the conversion, catch the error. LBYL (look before you leap) is fine when the check is cheap. For int parsing, EAFP is faster.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.