This TypeError means a variable became none and your code tried to loop, unpack, or build a list from it.
This error pops up when a variable you expect to hold a list, tuple, string, dict, set, or generator is actually None at runtime. The crash line is where Python tries to iterate. The real issue is usually earlier, where a value wasn’t created, a return was missed, or a lookup came back empty.
If you fix it once the right way, it tends to stop showing up across the whole module. This article walks you through what the message means, how to find the real source fast, and the fix patterns that stay clean as your codebase grows.
What The Error Means In Plain Terms
In Python, “iterable” just means “you can step through it.” A for loop steps through items one by one. Unpacking steps through items too, even if it’s only two items. Many helper functions step through inputs as well, like list(), set(), sum(), and zip().
None is different. It’s a single sentinel value that stands for “no value.” Its type is NoneType. It has no items inside it, so Python can’t step through it.
That’s why the traceback message points at iteration. The interpreter isn’t judging your logic. It’s saying, “I can’t loop this thing because it has nothing to loop through.”
- Spot The Operation — Find the exact operation on the crash line: a loop, an unpack, or a function that consumes iterables.
- Name The Variable — Identify the variable that is being iterated, not the variable you wish you had.
- Trace The Last Assignment — Jump to where that variable was last set, then work one step earlier if needed.
Where None Sneaks In Most Often
This message is common because None is a normal value in Python. Many functions return it on purpose, and many APIs use it to signal “not found.” The bug starts when your code treats that “not found” signal as if it were a list of results.
Missing Return From A Function
If a function reaches its end without an explicit return, Python returns None. That’s fine when you’re writing a function that only performs side effects. It’s a problem when the caller expects a collection.
- Check Every Branch — Make sure each
ifpath returns the same kind of value, not a list in one branch and nothing in another. - Return An Empty Collection — If “no matches” is normal, return
[]or()so a caller can loop with zero special cases.
In-Place Methods Returning None
Several in-place methods mutate an object and return None. A classic trap is list.sort(). The method sorts your list, but it returns None. If you do items = items.sort(), you just replaced your list with None.
- Call In-Place Methods On Their Own Line — Write
items.sort()without assigning the result. - Use The Non-Mutating Option — Use
sorted(items)when you want a new list and a return value.
Dictionary Lookups That Miss
dict.get(name) returns None when a field isn’t present, unless you pass a default. If you treat that result as a list and iterate, you’ll hit the error.
- Provide A Matching Default — Use
payload.get("items", [])when you want “missing” to behave like “empty.” - Fail Early On Required Fields — If the field must exist, raise a clear error with context right where you read the dict.
Parser Calls That Return None
Many parsing helpers return None to mean “no match.” Regex searches, HTML parsers, and JSON access layers do this. The same happens with ORM lookups that return None when no row matches.
- Branch Once — Check for
Noneimmediately after the call, then handle “found” and “not found” paths cleanly. - Pick The List-Returning API — When you truly want a collection, use the API that returns a list, even when it’s empty.
Fast Ways To Find The Real Source
The stack trace is your map. The last frame is the crash point. The earlier frames show how you got there. Your goal is to find the moment a value became None and decide if that was allowed.
Read The Traceback With A Repeatable Routine
- Start At The Bottom — The bottom line shows the exact operation that tried to iterate.
- Move Up To Your File — Skip library frames until you hit your own code, then stick with those lines.
- Circle The Iterable — Identify the expression after
inin a loop, or the value being unpacked. - Search For Assignments — Find where that name was set, especially from function calls and dict lookups.
Use A One-Line Probe Before The Crash
Add a tiny probe right before the failing line, run once, then remove it after the fix. Keep it plain so it doesn’t distract you during debugging.
- Print Value And Type — Use
print(items, type(items))to confirm it’sNonein that run. - Drop Into A Debugger — Use
breakpoint()to inspect variables interactively in Python 3.7+. - Add A Tight Assertion — Use
assert items is not Noneto fail earlier, closer to the cause.
Reproduce With The Smallest Input
When this error appears “random,” it’s often data-driven. Capture the failing input, shrink it, then fix the one entry point where raw data becomes the iterable your code expects.
- Log The Boundary Data — Log the raw response, file chunk, or query parameters that produced the bad value.
- Reduce The Case — Strip the input to the smallest example that still makes
Noneflow into a loop.
Fix Patterns That Stay Clean
Once you know which value is None, you’ll make one of two moves. Either you ensure the upstream code always returns an iterable, or you treat None as a valid value and handle it at the call site. The clean choice depends on the contract you want.
Prefer Empty Collections Over None For “No Items”
When a function’s job is “give me items,” returning an empty collection is usually the smoothest contract. The caller can loop it without checks, and that makes the code shorter and safer.
- Return [] For Lists — Use
return []on the “no results” branch. - Return () For Tuples — Use an empty tuple when callers unpack or compare tuples.
- Return An Empty Iterator — Use
return iter(())when you want to return an iterator shape.
Coalesce At The Loop Site When You Can’t Change The Source
Sometimes the None comes from a third-party package, a shared utility, or a legacy interface you don’t want to touch. In that case, keep your loop safe with a clear default.
- Use An Or Default — Write
for row in (rows or []):whenNoneshould mean “no rows.” - Branch With is None — Use
if rows is None:when you want a separate path, like raising or returning. - Match The Expected Type — Default to
[]when you loop lists, default to{}when you loop dict names.
Keep Return Types Stable Across All Branches
Mixed return types turn small bugs into recurring ones. If a function returns a list on Monday and None on Tuesday, every caller has to track that detail. It only takes one missed check to crash.
- Pick A Contract And Stick To It — “Always list” or “list or raise” are both clear.
- Write A Short Docstring — One sentence beats guesswork during refactors.
- Add Type Hints — Hints like
-> list[str]push warnings into your editor before runtime.
NoneType Object Is Not Iterable In Real-World Code Paths
This section gives you concrete scenarios that trigger the error. Each one includes a fix that keeps code readable and avoids sneaky side effects. You’ll also see nonetype object is not iterable in logs written in lower case, so spotting it gets easier.
Looping Over A Function Result
A common pattern is for item in fetch_items():. If fetch_items() returns None for the empty case, the loop breaks. Most apps are happier when the function returns [] for “no items.”
- Return A List Every Time — Build a list and return it, even if the list is empty.
- Raise On Invalid State — If empty is not allowed, raise a clear error inside the function, not in the caller.
Unpacking A Maybe-None Value
Unpacking is also iteration. If you do a, b = get_pair() and the function returns None, Python can’t pull out two values. This tends to happen with parsing helpers that return (x, y) for a match and nothing for no match.
- Return A Two-Item Tuple — Use
return (None, None)when you want unpacking to stay valid. - Branch Before Unpack — Return the pair object, test it, then unpack only on the match path.
Sorting Then Iterating
The in-place sort trap often shows up during quick refactors: items = items.sort(), then for x in items:. The loop line crashes, but the mistake is the assignment. The fix is tiny.
- Use sorted() — Write
items = sorted(items)when you want assignment. - Sort Without Assignment — Write
items.sort(), then loopitemson the next line.
Iterating Over JSON Fields That Are Missing Or null
JSON adds another wrinkle: a missing field and a null value are different states. Either one can become None in Python, and a loop will crash unless you set a default. The table below maps common cases to safe loop inputs.
| Incoming Value | What You’ll See In Python | Safe Loop Expression |
|---|---|---|
| Field missing | payload.get("items") returns None |
payload.get("items", []) |
| items: null | payload["items"] is None |
payload.get("items") or [] |
| items: [] | An empty list | payload["items"] |
Iterating Over A Database Result That Can Be Empty
Database libraries differ. Some return empty lists. Some return None from “fetch one.” If you treat a “fetch one” result as a list of rows, you’ll get this error. Fix it by choosing the API that matches your loop.
- Use fetchall For Row Lists — Loop over a list of rows, not a single row object.
- Handle fetchone Separately — Treat a single-row result as a single object, not a collection.
Stopping A NoneType Not Iterable Error From Returning
After you patch the crash, it’s worth adding a couple of small guardrails. They reduce the chance of the same bug reappearing during the next refactor or data shape change.
- Write Tests For Empty Paths — Add a test where the list is empty, the field is missing, or the parser finds no match.
- Validate At Boundaries — When raw input enters your code, validate shape once, then work with a clean internal shape.
- Log With Context — Log which user, file, request id, or record caused a missing value so you can reproduce quickly.
- Avoid Silent None Returns — If a function must return items, don’t let it “fall off the end.” Make every branch explicit.
- Review In-Place Methods — Watch for methods that return
Noneand keep them off the right side of=.
If you keep seeing nonetype object is not iterable across different files, treat it as a sign that your return contracts aren’t consistent. Pick one contract for each function, stick to it, and the error usually disappears with fewer lines changed than you’d expect.
One last check: after your fix, run the path that used to fail with empty input, missing fields, and a normal case. If all three pass, you’re done each time.
