← Back

Home › Errors › TypeError

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

# 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:
    ...
  1. If it prints <class 'list'> and None — no, if it prints <class 'NoneType'>, the assignment is the problem; look at what produced it.
  2. Trace the name back to its assignment. Read the right-hand side and ask: does this expression ever return None?
  3. If the right-hand side is a call to your own function, open it and confirm every code path ends in return.
  4. If it is a method call on a list or dict, check the Python docs for that method — in-place mutators return None by 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

🇮🇳 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.

TypeError Hindi में ठीक करना सीखें →