Fix Python ValueError: too many values to unpack (expected 2)

beginner🐍 Python2026-03-18| Python 3.x (all platforms: Linux, macOS, Windows)

Error Message

ValueError: too many values to unpack (expected 2)
#python#tuple#unpacking#list#value-error

TL;DR

There are more values in the iterable than variables on the left side of the assignment. Either add variables to match, use *rest to absorb the extras, or fix what you're unpacking from.

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

# Fixed β€” match the count
a, b, c = (1, 2, 3)

# Fixed β€” collect extras with star
a, b, *rest = (1, 2, 3, 4, 5)  # rest = [3, 4, 5]

Root Cause

Python unpacking is positional. The number of variables on the left must exactly match the number of values on the right. One extra value is enough to raise ValueError: too many values to unpack (expected N).

Four situations trigger this most often:

  • Assigning a tuple or list to fewer variables than it contains
  • Iterating a dictionary without .items() β€” each key gets treated as an iterable of characters
  • Unpacking CSV rows or API responses that have extra fields you didn't account for
  • Using for a, b in some_list when each element has more than 2 items

Fix 1 β€” Match Variable Count

Count the values, declare the right number of variables. Obvious with literals, but easy to miss when the data comes from a function call rather than something you wrote yourself.

# Wrong
first, last = "John", "Paul", "George", "Ringo"

# Right
first, second, third, fourth = "John", "Paul", "George", "Ringo"

Good for fixed structures where you always know the exact count ahead of time.

Fix 2 β€” Use the Star (*) Catch-All Syntax

Only need specific positions? Let * absorb the rest into a list:

# Grab first and last, collect middle
first, *middle, last = [10, 20, 30, 40, 50]
print(first)   # 10
print(last)    # 50
print(middle)  # [20, 30, 40]

# Grab first two, throw away the rest
a, b, *_ = get_csv_row()  # _ is the discard convention

Star syntax handles variable-length data cleanly β€” CSV rows, API payloads, anything where extra fields may appear without warning. The *_ pattern is idiomatic Python for "I know there's more, I don't need it."

Fix 3 β€” Dictionary Iteration Without .items()

This one catches a lot of people. Iterating a dict without .items() gives you keys, not (key, value) pairs. If a key is a string like "name", Python sees 4 individual characters β€” unpacking into two variables fails immediately:

# Broken β€” iterates keys, not (key, value) pairs
data = {"name": "Alice", "age": 30}
for key, value in data:  # ValueError: "name" has 4 chars, not 2
    print(key, value)

# Fixed
for key, value in data.items():
    print(key, value)
# name Alice
# age 30

Use .items() for key-value pairs, .keys() for keys alone, .values() for values alone.

Fix 4 β€” Unpacking Inside a Loop

Each element in your list has 3 fields, but you're only unpacking 2. Python can't guess which field to drop:

# Data has 3 fields per row
records = [
    ("alice", "alice@example.com", "admin"),
    ("bob",   "bob@example.com",   "user"),
]

# Broken β€” only 2 variables for 3 values
for name, email in records:  # ValueError
    print(name, email)

# Fixed β€” add the third variable
for name, email, role in records:
    print(name, email, role)

# Fixed β€” use star if role isn't needed
for name, email, *_ in records:
    print(name, email)

Fix 5 β€” Unpacking Function Return Values

Return values drift. A function that once returned 2 values gets a third field added later β€” a timestamp, a status code, a refresh rate. Every caller unpacking into exactly 2 variables breaks silently until runtime:

def get_dimensions():
    return 1920, 1080, 144  # refresh rate added later

# Broken
width, height = get_dimensions()  # ValueError

# Fixed
width, height, refresh = get_dimensions()

# If you genuinely don't need the extra value
width, height, *_ = get_dimensions()

If you own the function, treat adding a return value as a breaking change. Document it. Callers need to know.

Fix 6 β€” CSV / File Parsing

CSV files are particularly prone to this. Trailing commas, optional fields, schema changes β€” all produce rows with more columns than you expected:

import csv

# Broken if any row has more than 2 columns
with open("data.csv") as f:
    reader = csv.reader(f)
    for row in reader:
        name, score = row  # ValueError on extra-column rows

# Fixed β€” index into the row instead
with open("data.csv") as f:
    reader = csv.reader(f)
    for row in reader:
        name = row[0]
        score = row[1]

# Better β€” use DictReader for named columns
with open("data.csv") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["score"])

How to Confirm the Fix Worked

No ValueError on the next run β€” that's the confirmation. For external data sources like APIs, files, or databases, print a raw sample before writing the unpacking logic:

# Check the shape before committing to unpacking
data = some_function()
print(type(data), len(data), data)

# Then unpack with confidence
a, b, c = data

One print statement upfront saves ten minutes of debugging later.

Quick Diagnostic Checklist

  • Count values vs. variables β€” they must match, or use *rest
  • Iterating a dict? Add .items() to get key-value pairs
  • Loop unpacking for a, b in list? Check each element's actual length first
  • Parsing CSV or JSON? Columns may have changed β€” print a raw row before unpacking
  • Calling a function that returns a tuple? Verify the return value count hasn't grown

Related Error Notes