PythonMastery
reference 3 min read · lesson 2 of 60 in Errors

TypeError: 'NoneType' object is not iterable

1 · The lesson

read

What this error means

You tried to loop over a value that is None, or passed it to a function that loops over it, like list(), sorted() or sum(). (Unpacking None, as in a, b = None, gives a similar message: cannot unpack non-iterable NoneType object.) None is Python's "nothing" value. It has no elements, so you can't iterate over it. Almost every time you see this, you expected a function to return a list, dict or tuple, but it returned None, usually because a return statement was missing or skipped.

When you see it

python
Traceback (most recent call last):
  File "main.py", line 8, in <module>
    for name in get_names():
TypeError: 'NoneType' object is not iterable

Why it happens

A Python function that reaches its end without running a return statement returns None. So does a function whose return is hidden inside an if branch that didn't run. The caller then tries to iterate over None, and Python raises this error.

python
def get_names(active=True):
    if active:
        return ["alice", "bob"]
    # implicit `return None` when active is False

for name in get_names(active=False):   # crashes
    print(name)

Other common triggers: list-mutating methods (list.sort(), list.append(), list.reverse()) return None, not the list. Assigning their result and then iterating gives the same error.

How to fix it

Add the missing return, or return an empty collection so the caller can always iterate:

python
def get_names(active=True):
    if active:
        return ["alice", "bob"]
    return []                       # never return None for a "list-returning" function

Don't assign the result of in-place methods:

python
nums = [3, 1, 2]
nums.sort()                # changes nums in place and returns None
# for n in nums.sort():    # wrong: iterates over None
for n in nums:             # right
    print(n)

# If you want a new sorted list and the original unchanged:
for n in sorted(nums):
    print(n)

Check for None at the call site if None is a valid return value:

python
result = lookup(user_id)
if result is not None:
    for row in result:
        ...
+ setup added so this can run · defines lookup, user_id
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

def lookup(*_a, **_kw):
    print('-> lookup() called')
    return _AutoMock('lookup()')
user_id = _AutoMock('user_id')

When you'd see this in real code

  • A find_user() helper returns None when the user doesn't exist, but the caller iterates over the result without checking it.
  • sorted(get_items()) fails when get_items() returned None, because sorted() loops over its argument.
  • dict.get("key") returns None when the key is missing and you looped over it expecting a list.
  • You wrote names = names.sort() instead of names.sort() or names = sorted(names).

See Also

Found this useful? Share it with a friend who’s learning Python.