TypeError: 'NoneType' object is not iterable
Exception: TypeErrorCategory: runtime (iteration)Raised at: the for, unpacking, in, * or list() that consumes the None
What this error means
You asked Python to iterate over something, and that something was None. Iterating needs an object that can produce items in sequence; None is a single value meaning *no value*, so it has nothing to produce.
The for line in the traceback is not usually where the bug is. It is where the bug surfaces. The real mistake happened earlier, when something that should have returned a collection returned None instead.
Traceback (most recent call last):
File "demo.py", line 8, in <module>
for row in rows:
TypeError: 'NoneType' object is not iterable
The same message appears for every construct that iterates, not just for:
for x in value: ... # the usual one
a, b = value # unpacking
x = 1 in value # membership test
list(value), tuple(value), set(value), sum(value)
[*value], {**value}
zip(value, other)
print(*value) # argument unpacking
The four ways None gets there
- A method that mutates in place.
list.sort(),list.append(),list.reverse(),list.extend()andlist.insert()all returnNone. Capturing the result capturesNone. - A function with no
return. A Python function that reaches its end withoutreturngives backNone. The most common case is printing instead of returning. - A lookup that found nothing.
dict.get(k)without a default,dict.pop(k, None), andre.match()on a non-match all returnNone. - A variable that was never assigned on this path. Set inside an
ifthat did not fire, so the name exists but holdsNone.
# 1 — in-place methods return None
rows = fetch()
rows = rows.sort() # ❌ rows is now None
rows.sort() # ✅ mutate in place
rows = sorted(rows) # ✅ or take a new list
# 2 — a function that prints instead of returning
def evens(n):
print([x for x in range(n) if x % 2 == 0]) # ❌ returns None
def evens(n):
return [x for x in range(n) if x % 2 == 0] # ✅
# 3 — a lookup that misses
user = users.get(user_id) # None when the id is absent
for role in user["roles"]: # 💥 on the NEXT line, far from the cause
# 4 — assigned only inside a branch
result = None
if items:
result = [x * 2 for x in items]
for r in result: # 💥 when items was empty
Finding the actual source
Print the type on the line before the failing loop. That one line tells you which of the four causes you have:
print(type(rows), repr(rows))
for row in rows:
...
- If it prints
<class 'list'>andNone— no, if it prints<class 'NoneType'>, the assignment is the problem; look at what produced it. - Trace the name back to its assignment. Read the right-hand side and ask: does this expression ever return
None? - If the right-hand side is a call to your own function, open it and confirm every code path ends in
return. - If it is a method call on a list or dict, check the Python docs for that method — in-place mutators return
Noneby design.
A quick way to catch cause 2 in general: run the module with python -X dev or add assert result is not None right after the call during development. An assertion fails at the assignment, which is where you can actually fix it.
The fixes
# guard at the loop
for row in rows or []:
...
# or make the intent explicit
if rows is None:
rows = []
for row in rows:
...
# make the producer never return None
def fetch():
if not connected:
return [] # ✅ an empty list, not None
return query()
# give the lookup a default
user = users.get(user_id, {})
for role in user.get("roles", []):
...
Prefer fixing the producer over guarding the consumer. for row in rows or [] hides the fact that fetch() lied about its return type, and the next caller hits the same None. Returning an empty collection from the function is the durable fix; the guard is the right answer only when you genuinely cannot change the producer.
Empty is not the same as None
This distinction is worth internalising, because it is the source of a whole family of bugs. An empty list iterates zero times and is perfectly valid; None raises. Both are falsy, so if not rows: treats them the same — which is often what you want, and occasionally exactly what you do not want:
rows = []
for r in rows: pass # ✅ fine, zero iterations
rows = None
for r in rows: pass # 💥 TypeError
bool([]) is False # both falsy
bool(None) is False
if rows is None: # distinguishes "no data" from "empty data"
...
if not rows: # treats both the same
If your API uses None to mean *not yet fetched* and [] to mean *fetched, nothing matched*, keep those apart deliberately and check is None. Collapsing them into one falsy test is how a failed fetch silently looks like a successful empty one.
Related messages worth knowing
- TypeError: 'int' object is not iterable — the sibling message — same construct, a number instead of None.
- TypeError: 'NoneType' object is not subscriptable — the same None, caught by [] instead of by a loop.
- AttributeError: 'NoneType' object has no attribute — None reaching an attribute access rather than an iteration.
🇮🇳 Hindi में समझें
TypeError: 'NoneType' object is not iterable ka matlab hai aapne None par loop chalane ki koshish ki. None ek single value hai jiska matlab hai *koi value nahi* — usme iterate karne ke liye items hi nahi hain. Traceback me jo for line dikhti hai, bug wahaan nahi hota; wo wahaan *surface* hota hai. Asli galti pehle hui thi, jab kisi cheez ne collection ki jagah None return kar diya. Char common wajah: (1) in-place methods jaise sort(), append(), reverse() hamesha None return karte hain, isliye rows = rows.sort() likhne se rows None ban jaata hai — rows.sort() likho ya sorted(rows) use karo. (2) Function me return bhool gaye — Python me bina return wala function None deta hai, aksar tab jab aapne return ki jagah print likh diya ho. (3) Lookup miss ho gaya — dict.get(k) bina default ke, ya re.match() jo match na kare. (4) Variable sirf kisi if ke andar assign hua jo chala hi nahi. Debug karne ka sabse tez tareeka: failing line se ek line pehle print(type(rows)) lagao. Fix karne ke liye producer ko theek karna consumer ko guard karne se behtar hai — for r in rows or [] bug chhupa deta hai, jabki function se [] return karna hamesha kaam karta hai. Aur yaad rakho: khaali list None nahi hai. [] par loop zero baar chalta hai, error nahi aata.