Python ValueError: Invalid Literal for int(), Causes & Fixes (2026)

You ran your script, the user typed something, and Python slapped you with ValueError: invalid literal for int() with base 10. It’s one of the most common errors in Python, and almost every BSIT student trips over it the first time they use input(), read a CSV file, or parse an API response.

The error means: you handed int() a string it can’t convert to a whole number. Python is strict, it won’t silently strip whitespace, ignore decimals, or guess your locale. This guide walks through all 7 common causes with working code examples and clear fixes you can drop straight into your project.

ValueError · Invalid Literal for int() · 7 Fixes · 2026

📌 Quick answer: ValueError: invalid literal for int() with base 10: '...' means the string you passed to int() is not a plain whole number. The fix in 90% of cases: call .strip() to remove whitespace, validate the format with str.isdigit() or a regex, and wrap user input in try/except ValueError. If the string is a decimal like "3.14", use int(float(s)). If it’s hex or binary, pass the base, int(s, 16) or int(s, 2).

What “Invalid Literal for int()” Actually Means

The Python built-in int() converts a value to an integer. When you pass a string, Python only accepts a strict format: an optional sign (+ or -) followed by ASCII digits, with no decimals, commas, units, or letters mixed in. Anything else raises ValueError.

Here’s the simplest failing example:

age = int("twenty")
# ❌ ValueError: invalid literal for int() with base 10: 'twenty'

price = int("19.99")
# ❌ ValueError: invalid literal for int() with base 10: '19.99'

count = int("")
# ❌ ValueError: invalid literal for int() with base 10: ''

The error message always quotes the exact bad string in single quotes, that’s your biggest debugging clue. If you see '12\n', you have a trailing newline. If you see '', the string is empty. Read the quoted part carefully before anything else.

Cause #1: Whitespace or Newlines in the String

This is the #1 cause for beginners. You read a line from a file or stdin, and the trailing \n sneaks in. int() actually does tolerate leading and trailing spaces, but only ASCII spaces, not all whitespace, and definitely not embedded whitespace.

# Reading a file line-by-line
with open("scores.txt") as f:
    for line in f:
        score = int(line)   # ❌ ValueError: invalid literal for int() with base 10: '85\n'

# Pasted input with a tab
n = int("42\t")             # ❌ ValueError (tab is not stripped automatically)

The fix: always .strip() before converting:

with open("scores.txt") as f:
    for line in f:
        score = int(line.strip())   # ✅ strips \n, \t, and spaces

n = int("42\t".strip())             # ✅ returns 42

Make .strip() a reflex whenever the string came from a file, network, or user input. It costs nothing and prevents this exact bug.

Cause #2: Non-Numeric Characters (Currency, Commas, Units)

Real-world data is messy. CSV exports, web scrapes, and form fields often contain currency symbols, thousands separators, or units that int() rejects:

price = int("$1,200")     # ❌ ValueError: '$' and ',' are invalid
size  = int("500MB")      # ❌ ValueError: 'MB' is invalid
phone = int("0917-123")   # ❌ ValueError: '-' inside the digits is invalid

The fix, clean the string first:

# ✅ Quick clean for known characters
raw = "$1,200"
price = int(raw.replace("$", "").replace(",", ""))   # 1200

# ✅ Strip everything that isn't a digit or minus sign
import re
def clean_int(s):
    cleaned = re.sub(r"[^\d-]", "", s)
    return int(cleaned) if cleaned not in ("", "-") else 0

print(clean_int("$1,200"))   # 1200
print(clean_int("500MB"))    # 500
print(clean_int("-42.99"))   # -4299  ← note: decimals get flattened!

That last line is a warning: if the string can have decimals, stripping non-digits will mangle the value. Use float() first when decimals are possible (see Cause #4).

Cause #3: Empty String from input() or split()

The user pressed Enter without typing anything. Or you split a CSV line and one column was blank. int("") always raises ValueError:

age = int(input("Enter age: "))   # ❌ ValueError if user just hits Enter

# Splitting CSV with empty fields
row = "Ana,,85".split(",")   # ['Ana', '', '85']
score = int(row[1])          # ❌ ValueError: invalid literal for int() with base 10: ''

The fix, validate before converting:

# ✅ Re-prompt loop for user input
while True:
    raw = input("Enter age: ").strip()
    if raw.isdigit():
        age = int(raw)
        break
    print("Please type a whole number.")

# ✅ Default value for missing CSV fields
def to_int(s, default=0):
    s = s.strip()
    return int(s) if s else default

score = to_int(row[1])   # 0 instead of crashing

For more on building safer input loops, see our Python tutorial series.

Cause #4: Float String Passed to int()

This one surprises everyone: int() can convert a float object, but it cannot convert a string that looks like a float:

int(3.14)       # ✅ 3 (truncates toward zero)
int("3.14")     # ❌ ValueError: invalid literal for int() with base 10: '3.14'
int("3.0")      # ❌ ValueError: even though it's mathematically an int

This trips up beginners who read prices, scores, or measurements from JSON or CSV and expect Python to “just figure it out.” Python doesn’t guess, you have to be explicit about the conversion path.

The fix, go through float() first:

# ✅ Truncate decimals (toward zero)
n = int(float("3.99"))   # 3

# ✅ Round to nearest integer
n = round(float("3.99"))   # 4

# ✅ Floor / ceiling explicitly
import math
n = math.floor(float("3.99"))   # 3
n = math.ceil(float("3.01"))    # 4

Choose int(float(s)), round(), math.floor(), or math.ceil() based on what your domain actually wants. Don’t default to truncation just because int() does, for monetary or scoring contexts, round() is usually what users expect.

Cause #5: Scientific Notation Strings

Strings like "1e3", "2.5E6", or "1.5e-2" are valid floats, but int() refuses them outright:

int("1e3")       # ❌ ValueError: invalid literal for int() with base 10: '1e3'
int("2.5E6")     # ❌ ValueError
int(1e3)         # ✅ 1000 (passing the float directly works fine)

You’ll hit this when parsing scientific data, large numbers from APIs, or NumPy arrays serialized to JSON.

The fix, convert through float():

n = int(float("1e3"))     # 1000
n = int(float("2.5E6"))   # 2500000
n = int(float("1.5e-2"))  # 0 (truncated: 0.015 → 0)

Same caveat as Cause #4: decide whether truncation or rounding is correct for your use case before defaulting to int().

Cause #6: Wrong Base (Binary, Hex, Octal Strings)

By default, int(s) assumes base 10. If your string is hex ("0xFF"), binary ("0b1010"), or octal ("0o17"), the default conversion fails:

int("0xFF")     # ❌ ValueError: invalid literal for int() with base 10: '0xFF'
int("FF")       # ❌ ValueError
int("0b1010")   # ❌ ValueError
int("777")      # ✅ 777 in base 10 (NOT octal: Python 3 won't guess)

The fix, pass the base explicitly:

int("FF", 16)       # 255: hex
int("0xFF", 16)     # 255: also works with 0x prefix
int("0xFF", 0)      # 255: base 0 auto-detects from prefix
int("1010", 2)      # 10: binary
int("0b1010", 2)    # 10
int("17", 8)        # 15: octal
int("0o17", 0)      # 15: base 0 auto-detects

Pro tip: int(s, 0) is the most flexible, it inspects the prefix (0x, 0b, 0o) and picks the base automatically. Use it when your input source might mix bases. Just remember the string must include the prefix for auto-detection to work.

Cause #7: Locale-Specific Number Formatting

In the Philippines and the US, 1,234.56 means “one thousand two hundred thirty-four point five six.” In Germany, France, and most of Europe, the same number is written 1.234,56, commas and periods swapped. If you’re parsing user input or files from mixed locales, int() won’t know:

int("1.234")       # ❌ ValueError: Python reads '.' as decimal point
int("1,234")       # ❌ ValueError: ',' is not a digit in default locale
int("1 234")       # ❌ ValueError: embedded space is invalid

The fix, use the locale module or normalize manually:

# ✅ Manual normalization (most reliable, works in any environment)
def parse_us_number(s):
    return int(s.replace(",", "").replace(" ", ""))

def parse_eu_number(s):
    # EU style: '.' = thousands, ',' = decimal
    s = s.replace(".", "").replace(" ", "")
    return int(s.split(",")[0])   # drop decimal part if any

print(parse_us_number("1,234"))   # 1234
print(parse_eu_number("1.234,56"))  # 1234

# ✅ Or use the locale module for full I18N support
import locale
locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
n = locale.atoi("1,234")   # 1234

For Filipino BSIT projects scraping international data, the manual approach is more portable, locale.setlocale() behaves differently across Windows, Linux, and Mac.

Quick Prevention Checklist

Internalize these habits and you’ll stop seeing this error in your own code:

  • Always .strip() before int() when the string came from a file, network, or user input
  • Wrap user-facing int() calls in try/except ValueError with a friendly error message and a re-prompt loop
  • Use int(float(s)) for decimal strings: choose round() instead if half-up rounding matches your domain
  • Pass base explicitly for non-decimal strings: int("FF", 16), int("1010", 2), or int(s, 0) for auto-detect
  • Validate with str.isdigit() for unsigned ints, or a regex like re.fullmatch(r"-?\d+", s) for signed ints
  • Read the error message: the single-quoted value tells you exactly what string was rejected
  • Normalize locale-specific numbers with .replace() before converting, or use the locale module

When You Should Use try/except ValueError

Unlike IndexError (which usually indicates a logic bug you should fix), ValueError from int() is almost always a data problem, and data problems should be handled, not prevented. So try/except ValueError is the right tool whenever the string comes from outside your control:

# ✅ Good: user input may be anything
def get_age():
    while True:
        raw = input("Enter age: ").strip()
        try:
            return int(raw)
        except ValueError:
            print(f"'{raw}' is not a valid whole number. Try again.")

# ✅ Good: CSV row may have garbage
def parse_score(cell, default=0):
    try:
        return int(cell.strip())
    except (ValueError, AttributeError):
        return default

# ❌ Bad: hides a real bug in your own code
def total(items):
    try:
        return sum(int(x) for x in items)
    except ValueError:
        return 0   # silently returns 0 for any bad item: debugging nightmare

Rule of thumb: catch ValueError at the boundary where untrusted data enters your program (input, files, network). Inside your own logic, fix the data type at the source instead of swallowing the error.

📌 Beyond debugging, level up your Python

Once you’ve nailed input validation, see our best Python projects with source code for capstone ideas, the best Python IDE 2026 comparison, or browse our free Python tutorial series from beginner to advanced.

Frequently Asked Questions

What does “invalid literal for int() with base 10” mean?
It means the string you passed to int() does not match the strict format Python expects: an optional sign followed by ASCII digits, with no decimals, commas, units, or other characters. The single-quoted value in the error message tells you exactly which string was rejected, read it carefully, since it often reveals a hidden newline (\n), tab (\t), or empty string ('') you didn’t notice.
Why does int(“3.14”) fail but int(3.14) works?
int() accepts a float object and truncates it toward zero. But when given a string, it only accepts whole-number formats, no decimal point allowed. The fix is explicit: int(float("3.14")) first converts the string to a float, then to an integer. Use round() instead of int() if you want half-up rounding rather than truncation.
How do I handle ValueError when reading user input?
Wrap the int() call in try/except ValueError inside a while True loop. On exception, print a helpful message and continue the loop to re-prompt. Example: while True: raw = input("Enter age: ").strip(); try: age = int(raw); break; except ValueError: print("Please type a whole number."). Always .strip() first to remove any trailing newline.
Why does int() fail when reading numbers from a file?
When you iterate over a file with for line in f:, each line includes the trailing newline character \n. Even though int() tolerates leading and trailing spaces, it does not strip newlines or tabs. The fix is always int(line.strip()). Make .strip() a reflex any time the string came from a file, network socket, or input().
How do I convert a hex or binary string to int?
Pass the base as the second argument: int("FF", 16) returns 255, int("1010", 2) returns 10, and int("17", 8) returns 15. Strings with prefixes also work: int("0xFF", 16) and int("0b1010", 2). For maximum flexibility, use int(s, 0), base 0 auto-detects the format from the 0x, 0b, or 0o prefix.
Does int() work with scientific notation like “1e3”?
No. int("1e3") raises ValueError because scientific notation is a float syntax, not an integer syntax. Convert through float first: int(float("1e3")) returns 1000. The same applies to "2.5E6", "1.5e-2", and similar formats, they’re valid for float() but not for int().
How do I strip commas and currency symbols before int()?
Use str.replace() for known characters: int("$1,200".replace("$", "").replace(",", "")) returns 1200. For a general-purpose cleaner, use a regex: import re; int(re.sub(r"[^\d-]", "", s)) strips everything except digits and minus signs. If the value might have decimals, convert through float() instead so you don’t accidentally combine the integer and decimal parts.
How is ValueError different from TypeError?
ValueError is raised when an argument has the right type but a wrong value, like passing the string "abc" to int(). TypeError is raised when the type itself is wrong, like calling int(None) or "5" + 3. For TypeError fixes, see our “object is not callable” guide and the full ValueError hub for the rest of the ValueError family.
Should I validate with isdigit() or use try/except?
Both have a place. str.isdigit() is fast and clean for unsigned integers, if raw.isdigit(): n = int(raw). But it rejects valid signed integers like "-42" and doesn’t handle whitespace. For signed integers, use a regex (re.fullmatch(r"-?\d+", s)) or just use try/except ValueError. The exception approach is more Pythonic for user-facing input where you want a re-prompt loop anyway.

Final Recommendation

If you take only one habit from this guide, make it this: treat every string that came from outside your program as untrusted, and always .strip() + try/except ValueError before converting to int. That single pattern eliminates 80% of “invalid literal for int()” errors in beginner Python code.

For the remaining 20%, decimals, scientific notation, hex/binary, locale-specific formatting, pick the right tool: int(float(s)) for decimals, int(s, 0) for hex/binary with prefixes, and explicit normalization for international number formats. The error message always quotes the exact string that failed, read it first, fix the right thing.

If you’re hitting related Python errors, our list index out of range fix guide and KeyError explained cover the next two most common beginner errors, and TypeError: object is not callable covers a sibling type-conversion bug.

🎯 Your next steps:

  1. Audit your current code: every int(...) call that touches user input, files, or APIs should have .strip() + try/except ValueError
  2. For decimal strings, switch to int(float(s)) or round(float(s)) based on what your domain wants
  3. For hex/binary parsing, use int(s, 0) for auto-detect or pass the explicit base
  4. Browse more ValueError fixes or our full Python tutorial series
🎯 Your next steps:

  1. Audit your current code: every int(...) call that touches user input, files, or APIs should have .strip() + try/except ValueError
  2. For decimal strings, switch to int(float(s)) or round(float(s)) based on what your domain wants
  3. For hex/binary parsing, use int(s, 0) for auto-detect or pass the explicit base
  4. Browse more ValueError fixes or our full Python tutorial series

Still stuck on a specific ValueError? Drop the exact error message (including the single-quoted value) and the code snippet in the comments, we’ll help you debug it.

Leave a Comment