
This error is simple: you tried to use a for loop on a variable, but that variable was None. In Python, this will raise a TypeError NoneType not iterable message.
“Iterable” just means “something you can loop over” (like a List, Tuple, or String). None is not on that list.
โก Quick Fix: TypeError: ‘NoneType’ object is not iterable โ Python Empty List Return Fix and None Guard for for Loop Crashes
Your for loop received None instead of a list โ a function returned nothing, and Python has no items to iterate over.
# WRONG โ function returns None for unmatched IDs, loop crashes immediately
def get_user_list(group_id):
if group_id == 1:
return ["Alice", "Bob"]
# no return for other IDs โ Python implicitly returns None
users = get_user_list(2)
for user in users: # TypeError: 'NoneType' object is not iterable
print(user)
# FIX 1 โ return an empty list instead of None (best fix โ change the function)
def get_user_list(group_id):
if group_id == 1:
return ["Alice", "Bob"]
return [] # empty list is iterable โ loop runs zero times, no crash
# FIX 2 โ guard with None check (use when you can't change the function)
users = get_user_list(2)
if users is not None:
for user in users:
print(user)
# FIX 3 โ fallback with or [] (one-liner, cleanest for inline use)
for user in (get_user_list(2) or []):
print(user) # silently skips when function returns NoneThe two fixes below explain when to change the function versus when to guard the caller โ and the or [] pattern that handles both in one line.
The Cause
This almost always happens when you try to loop over the result of a function that failed silently by returning None.
Problem Code:
def get_user_list(group_id):
if group_id == 1:
return ["Alice", "Bob"]
else:
# Whoops, we forgot to return an empty list!
return None
# This works
group_1_users = get_user_list(1)
for user in group_1_users:
print(user)
# This crashes
group_2_users = get_user_list(2) # group_2_users is now None
for user in group_2_users:
print(user)
# CRASH! TypeError: 'NoneType' object is not iterableThe Fix: Always Return a Default Iterable
The best fix is to make your function “safer.” Instead of returning None, return an empty list [].
Corrected Function:
def get_user_list(group_id):
if group_id == 1:
return ["Alice", "Bob"]
else:
# THE FIX: Return an empty list, which is iterable
return []Now, when you call get_user_list(2), the for loop will just run zero times, and your program will not crash.
Quick Fix (If you can’t change the function): You can also check for None before you loop.
group_2_users = get_user_list(2)
if group_2_users is not None:
for user in group_2_users:
print(user)TypeError: ‘NoneType’ object is not iterable โ Fix the Function, Guard the Caller, or Use or []
TypeError: ‘NoneType’ object is not iterable fires at the for loop โ but the bug lives at the function that returned None. Fix the source, not the loop.
Three fixes exist. Pick based on what you control.
Return an empty list from the function when the result has no items. An empty list is fully iterable โ the for loop runs zero times and continues cleanly. This is the correct fix for any function you wrote. A function that returns a list on success and None on failure has inconsistent return types. Make it consistent: return [] on the no-result path, return [“item”] on the success path. Every caller benefits automatically, no guard code needed.
Use if result is not None: when you can’t change the function. A third-party library, a database driver, or a colleague’s function that you cannot modify might return None on empty results. Wrap the loop in a None check at the call site. The loop body only runs when real data exists.
Use or [] for the most concise inline guard. for item in (get_data() or []): replaces None with an empty list in one expression. Python evaluates get_data() โ if it returns None or any other falsy value, or [] kicks in and supplies an empty iterable. The loop body never runs. Use this pattern for short scripts and list comprehensions where a full if block adds unnecessary lines.
The type annotation habit that prevents this permanently: add -> list to every function that should return a list. Type checkers like mypy flag None return paths immediately before the code runs.
def get_user_list(group_id: int) -> list:
if group_id == 1:
return [“Alice”, “Bob”]
return [] # mypy enforces this โ no None path allowed





