Fix TypeError: 'NoneType' object is not iterable in Python

beginner🐍 Python2026-04-22| Python 3.x on Linux, macOS, Windows

Error Message

TypeError: 'NoneType' object is not iterable
#python#typeerror#none#iteration#debugging

The Error

You're looping over something β€” a function result, a database row, an API response β€” and Python throws:

TypeError: 'NoneType' object is not iterable

Translation: you tried to iterate over None. Every iteration mechanism in Python β€” for loops, list comprehensions, tuple unpacking, * spread β€” needs an actual iterable. None isn't one.

Here's the simplest way to trigger it:

def get_users():
    pass  # forgot to return anything

for user in get_users():  # TypeError here
    print(user)

Root Cause

Any Python function without an explicit return statement silently returns None. That's the language spec, not a bug. But several other patterns produce the same trap:

  • A function returns None on a branch you didn't think about β€” an if with no matching else, for example
  • In-place methods like list.sort() or dict.update() modify the object and return None β€” always
  • An ORM query, database cursor, or API call returns None when the result set is empty
  • You assign the return value of one of those in-place methods to a variable

The last one trips up developers constantly. Here's what it looks like:

items = [3, 1, 2]
items = items.sort()  # sort() returns None, not the sorted list!

for item in items:  # TypeError: 'NoneType' object is not iterable
    print(item)

items is now None. The original list is sorted β€” but you threw away the reference to it.

How to Fix It

Fix 1: Check what the function actually returns

Before looping, print or inspect the value:

result = get_users()
print(type(result), result)  # Debug: see what you actually got

If the output is <class 'NoneType'> None, the function isn't returning what you expect. Find it and add a return statement:

def get_users():
    users = db.query("SELECT * FROM users")
    return users  # was missing before

Fix 2: Guard with an explicit None check

Sometimes None is a valid outcome β€” no results found, nothing to process. Guard before iterating:

users = get_users()

if users is not None:
    for user in users:
        print(user)

Or collapse it into one line:

for user in (users or []):
    print(user)

The or [] substitutes an empty list when users is None. The loop runs zero times and no exception is raised.

Fix 3: Default to an empty collection inside the function

Fixing every call site is tedious. Fix the function once instead:

def get_users():
    result = db.query("SELECT * FROM users")
    if result is None:
        return []  # always return a list
    return result

Callers can now iterate freely. No guards needed at every use site.

Fix 4: Fix the in-place method assignment trap

list.sort(), list.reverse(), dict.update(), and set.add() all modify in place. They return None. Don't assign their result:

# Wrong
items = items.sort()

# Correct: sort in place, keep the reference
items.sort()

# Or use sorted() β€” it returns a new list
items = sorted(items)

Fix 5: Handle None from chained calls

Method chaining hides None until it blows up. This is risky:

# response.json() might return None
for item in response.json().get("results"):
    process(item)

Break it apart and check at each step:

data = response.json()
results = data.get("results") if data else []
for item in (results or []):
    process(item)

Fix 6: Walrus operator (Python 3.8+)

When the function is external and you can't change its return type, the walrus operator is cleaner than a two-line check:

if (users := get_users()) is not None:
    for user in users:
        print(user)

Finding Where None Comes From

Read the full traceback. Python pinpoints the exact line:

Traceback (most recent call last):
  File "app.py", line 12, in process_orders
    for order in get_orders(user_id):
TypeError: 'NoneType' object is not iterable

Go to line 12. The iterable is get_orders(user_id). Add a debug print above it:

result = get_orders(user_id)
print(f"get_orders returned: {result!r}")
for order in result:
    ...

The !r format calls repr() on the value. It clearly distinguishes None from an empty string '' or empty list [] β€” all three look different in repr output.

Verification

Run the code again after your fix. No TypeError means it worked. To confirm the guard path handles None correctly, simulate it explicitly:

def get_users():
    return None  # simulate no results

users = get_users()
for user in (users or []):
    print(user)

print("Done β€” no error")

Expected output:

Done β€” no error

The loop body is skipped. No exception. That's the behavior you want.

Prevention

  • Add type hints: def get_users() -> list[User]: documents the expected return type. Run mypy and it will flag any code path that returns None instead.
  • Be honest with Optional: If a function legitimately can return None, annotate it as Optional[list]. That signals to callers: check before you iterate.
  • Never assign in-place method results: sort(), reverse(), update(), append() β€” all return None. Tattoo this on your brain.
  • Return empty collections, not None: A function fetching a list should return [] on an empty result, not None. Reserve None for "this value doesn't exist" β€” not "I found nothing."

Related Error Notes