Skip to main content

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 like for item in iterable: or element 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 the NoneType 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).
note

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
note

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
note

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

  1. Print Type: Right before the error line, print(f"DEBUG: Type of my_variable is {type(my_variable)}"). This confirms it's NoneType.
  2. Print Value: Also print(f"DEBUG: Value of my_variable is {repr(my_variable)}") to be absolutely sure it's None.
  3. 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:

  1. Guarding Operations: Check if variable is not None: before attempting iteration (for) or membership tests (in).
  2. Providing Defaults: Use variable or [] (or "", {}, etc.) to substitute an empty iterable when variable might be None.
  3. 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 like sort()).

By understanding that None cannot be iterated over and implementing these checks or fixes, you can prevent these common TypeError exceptions.