Skip to main content

Fix ValueError in Python

Error Reference

ValueError

ValueErrors signal that the type is correct but the actual value is unusable.

Common messages

  • ValueError: invalid literal for int() with base 10
  • ValueError: could not convert string to float
  • ValueError: not enough values to unpack

The pattern behind all of them: right type, wrong value. int() happily accepts strings — just not every string:

int('42')     # 42 — a string, but one that spells an integer
int('abc')
# ValueError: invalid literal for int() with base 10: 'abc'

float('') # empty input field, unfilled form, blank CSV cell...
# ValueError: could not convert string to float: ''

Compare with int([]), which is a TypeError — a list can never become an int, no matter its value. When a ValueError fires, investigate the failing value (the message quotes it) and decide: validate it, default it, or reject it with a clear error.

Unpacking mismatches

Unpacking demands an exact count on both sides, and the messages state the arithmetic:

a, b = [1, 2, 3]
# ValueError: too many values to unpack (expected 2)

a, b, c = [1, 2]
# ValueError: not enough values to unpack (expected 3, got 2)

This often appears when splitting strings that don't have the shape you assumed:

key, value = 'timeout=30'.split('=')      # fine
key, value = 'debug'.split('=')
# ValueError: not enough values to unpack (expected 2, got 1)

Fixes: cap the split with split('=', 1) for "everything after the first =", use a starred target like first, *rest = items when the count varies, or check the length before unpacking.

Validate before converting

You might reach for str.isdigit() to pre-check input, but it rejects perfectly convertible strings:

'42'.isdigit()     # True
'-3'.isdigit() # False — but int('-3') works
' 42 '.isdigit() # False — but int(' 42 ') == 42 (int strips whitespace)

The pythonic pattern is to just try the conversion and handle the failure — int() already knows every valid spelling, including negatives and surrounding whitespace:

try:
age = int(user_input)
except ValueError as exc:
raise ValueError("Please enter a valid integer age") from exc

Using from exc preserves the original error context in the traceback. In a loop, retry instead of raising:

while True:
try:
age = int(input('Age: '))
break
except ValueError:
print('Not a number, try again.')

Raising ValueError in your own code

Raise it yourself when an argument has the right type but an unusable value — callers get the same error contract the built-ins use:

def set_discount(percent):
if not 0 <= percent <= 100:
raise ValueError(f'percent must be between 0 and 100, got {percent}')
return percent / 100

set_discount(150)
# ValueError: percent must be between 0 and 100, got 150

Put the offending value in the message — future you, reading a log at 2 a.m., will be grateful. Reserve TypeError for wrong types (percent being a string) and ValueError for out-of-range or malformed values.

Frequently Asked Questions

What is the difference between ValueError and TypeError?

TypeError: the type is wrong, so no value of that type could work — int([]) fails for every list. ValueError: the type is fine but this value is not — int('abc') fails only because 'abc' does not spell an integer. Ask: would a different value of the same type succeed? If yes, it's a ValueError.

int([])      # TypeError: int() argument must be a string, a bytes-like object or a real number, not 'list'
int('abc') # ValueError: invalid literal for int() with base 10: 'abc'

How do I safely parse user input into a number?

Wrap the conversion in try/except ValueError instead of pre-checking with isdigit(). isdigit() returns False for negatives ('-3') and padded input (' 42 ') even though int() converts both fine. Trying the conversion is both more correct and simpler — one code path instead of a check that duplicates int()'s rules badly.

def parse_int(text, default=None):
try:
return int(text)
except ValueError:
return default

parse_int(' -3 ') # -3
parse_int('abc') # None

Next up in your learning path