How to Resolve Python Errors "TypeError: argument of type 'NoneType' is not iterable" and "TypeError: 'NoneType' object is not iterable"
Python's TypeError: 'NoneType' object is not iterable
and the closely related TypeError: argument of type 'NoneType' is not iterable
are common runtime errors. They occur when you attempt to perform an operation that requires an iterable (like looping with for
, checking membership with in
, or using functions like list()
, tuple()
, set()
) on a variable that currently holds the special value None
.
This guide explains why None
is not iterable and provides practical solutions to handle these errors by checking for None
or addressing the source of the unexpected None
value.
Understanding the Error: Iterables vs. None
- Iterables: In Python, an iterable is an object capable of returning its members one at a time. Common iterables include lists (
[]
), tuples (()
), strings (""
), dictionaries ({}
), sets ({}
), and file objects. Operations likefor item in iterable:
orelement in iterable
rely on the object being iterable. None
:None
is Python's special singleton object representing the absence of a value. It belongs to theNoneType
class. Crucially,None
is not iterable. It doesn't contain any members to loop over or check against.
Both TypeError
messages indicate that an operation expected an iterable but received None
instead.
Error 1: argument of type 'NoneType' is not iterable
(Using in
/ not in
)
This specific phrasing often occurs when using the membership test operators (in
or not in
).
Cause: Membership Testing Requires an Iterable
The in
operator checks if an element exists within a sequence or collection. The object on the right side of in
must be iterable.
# Error Scenario
data_source = None # Variable unexpectedly holds None
try:
# ⛔️ TypeError: argument of type 'NoneType' is not iterable
if "target_value" in data_source:
print("Found!")
else:
print("Not found.")
except TypeError as e:
print(e)
Python cannot check for membership within None
.
Solution: Check for None
Before Using in
Use an if
statement or boolean logic (and
) to ensure the variable is not None
before performing the membership test.
data_source = None
target = "target_value"
# ✅ Using 'and' (short-circuits if data_source is None)
if data_source is not None and target in data_source:
print(f"'{target}' found in data_source.")
else:
# This runs if data_source is None OR target isn't found in a valid data_source
print(f"'{target}' not found or data_source is None.")
# ✅ Using nested 'if'
if data_source is not None:
if target in data_source:
print(f"'{target}' found in data_source.")
else:
print(f"'{target}' not found in valid data_source.")
else:
print("data_source is None.")
Output:
'target_value' not found or data_source is None.
data_source is None.
Solution: Provide a Default Iterable
You can use the or
operator to provide a default empty iterable (like []
or ""
) if the variable is None
. The in
operator will then safely operate on the empty default.
data_source = None
target = "target_value"
# ✅ Provide an empty list [] as fallback if data_source is None
if target in (data_source or []):
print(f"'{target}' found.") # Will not run if data_source is None
else:
print(f"'{target}' not found (or data_source was None).") # This is executed
# Example with a string
text_content = None
if "error" in (text_content or ""): # Use "" as fallback for string checks
print("Error text found.")
else:
print("No error text found (or content was None).") # This is executed
Output:
'target_value' not found (or data_source was None).
No error text found (or content was None).
None or []
evaluates to []
. None or ""
evaluates to ""
.
Error 2: 'NoneType' object is not iterable
(Using for
, list()
, etc.)
This phrasing is common when trying to loop over None
or pass it to functions/constructors expecting an iterable.
Cause: Iteration Requires an Iterable
Operations that expect to go through items one by one (like for
loops or constructors like list()
, tuple()
, set()
, dict()
) require an iterable object.
# Error Scenario: For loop
results = None
try:
# ⛔️ TypeError: 'NoneType' object is not iterable
for item in results:
print(item)
except TypeError as e:
print(f"For loop error: {e}")
# Error Scenario: list() constructor
config_data = None
try:
# ⛔️ TypeError: 'NoneType' object is not iterable
config_list = list(config_data)
except TypeError as e:
print(f"list() constructor error: {e}")
Solution: Check for None
Before Iterating
Similar to the in
operator, explicitly check if the variable is not None
before attempting iteration.
results = None
# ✅ Check before looping
if results is not None:
print("Processing results:")
for item in results:
print(item)
else:
print("No results to process (results is None).") # This is executed
# ✅ Check before converting
config_data = None
config_list = [] # Default to empty list
if config_data is not None:
try:
config_list = list(config_data) # Convert only if not None
print("Converted config to list.")
except TypeError as e: # Catch error if it's not iterable for other reasons
print(f"Error converting non-None config_data: {e}")
else:
print("Config data is None, using default empty list.")
print(f"Final config_list: {config_list}")
Output:
No results to process (results is None).
Config data is None, using default empty list.
Final config_list: []
Solution: Provide a Default Iterable
Use the or
trick to substitute an empty iterable if the variable is None
.
results = None
# ✅ Use 'or []' for the loop
print("Looping with 'or []':")
for item in (results or []): # Loops over empty list if results is None
print(item) # Loop body won't execute if results is None
print("Loop finished.")
# ✅ Use 'or []' for conversion
config_data = None
config_list = list(config_data or []) # list([]) creates an empty list
print(f"List from (config_data or []): {config_list}") # Output: []
Output:
Looping with 'or []':
Loop finished.
List from (config_data or []): []
Common Sources of None
Values
The best solution often involves preventing the variable from becoming None
unexpectedly in the first place. Look out for:
Functions Without Explicit return
A function that completes without hitting a return
statement implicitly returns None
.
def process_data(data):
if len(data) > 0:
# print("Processing...")
# Forgets to return anything
pass # Implicitly returns None
my_list = process_data([1, 2]) # my_list becomes None
# Subsequent loop/in check on my_list will fail
Fix: Ensure the function always returns a suitable value (e.g., the processed data, or an empty list/dict on failure).
Functions with Conditional return
A function might only return a value under certain conditions, returning None
implicitly otherwise.
def find_user(users, user_id):
for user in users:
if user['id'] == user_id:
return user # Returns user dict if found
# Implicitly returns None if loop finishes without finding user
user = find_user([{'id': 1}, {'id': 2}], 3) # user becomes None
# Subsequent checks like 'if "name" in user:' will fail
Fix: Return a default value (like None
explicitly, or an empty dictionary {}
) from the function if the condition isn't met, and have the calling code check for that default.
In-Place Methods Returning None
(e.g., list.sort()
)
Methods that modify an object in-place (like list.sort()
, list.reverse()
) often return None
. Don't assign their result back to the variable you want to iterate over.
my_data = [3, 1, 2]
sorted_data = my_data.sort() # WRONG: sort() modifies my_data and returns None
print(f"sorted_data is: {sorted_data}") # Output: None
print(f"Original my_data is now sorted: {my_data}") # Output: [1, 2, 3]
try:
# ⛔️ TypeError: 'NoneType' object is not iterable
for item in sorted_data: # Trying to iterate over None
print(item)
except TypeError as e:
print(e)
# ✅ Correct: sort in place, then iterate over the original (now sorted) list
my_data = [3, 1, 2]
my_data.sort()
for item in my_data: # Iterate over the modified my_data
print(item)
Output:
sorted_data is: None
Original my_data is now sorted: [1, 2, 3]
'NoneType' object is not iterable
1
2
3
Explicit Assignment (my_var = None
)
Double-check your code for places where you might be intentionally or accidentally assigning None
to the variable before the point where iteration or membership testing occurs.
Debugging: Finding the Source of None
- Print Type: Right before the error line,
print(f"DEBUG: Type of my_variable is {type(my_variable)}")
. This confirms it'sNoneType
. - Print Value: Also
print(f"DEBUG: Value of my_variable is {repr(my_variable)}")
to be absolutely sure it'sNone
. - Trace Back: Examine the code leading up to the error. Where was this variable last assigned? Follow the logic (function calls, loops, conditionals) to understand how it received the
None
value. Use a debugger if necessary.
Checking if an Object is Iterable
While not a direct fix for the NoneType
error (as None
is never iterable), you can technically check if an arbitrary object is iterable using try...except
with the iter()
function.
from collections.abc import Iterable
def is_iterable(obj):
# Method 1: Using iter()
try:
iter(obj)
return True
except TypeError:
return False
# Method 2: Using isinstance (Python 3.3+)
# return isinstance(obj, Iterable)
print(f"'hello' is iterable? {is_iterable('hello')}") # True
print(f"[1, 2] is iterable? {is_iterable([1, 2])}") # True
print(f"None is iterable? {is_iterable(None)}") # False
print(f"123 is iterable? {is_iterable(123)}") # False
Output:
'hello' is iterable? True
[1, 2] is iterable? True
None is iterable? False
123 is iterable? False
This check can be useful in generic functions, but for the NoneType
error, directly checking if variable is not None:
is usually sufficient.
Conclusion
The TypeError
indicating NoneType
is not iterable arises when you treat None
as if it were a list, string, tuple, dictionary, or other collection you can loop through or check membership in.
The primary solutions involve:
- Guarding Operations: Check
if variable is not None:
before attempting iteration (for
) or membership tests (in
). - Providing Defaults: Use
variable or []
(or""
,{}
, etc.) to substitute an empty iterable whenvariable
might beNone
. - Fixing the Source: The most robust solution is often to investigate why the variable holds
None
and correct the preceding logic (e.g., ensure functions return iterables, avoid assigning the result of in-place methods likesort()
).
By understanding that None
cannot be iterated over and implementing these checks or fixes, you can prevent these common TypeError
exceptions.