TypeError: 'NoneType' object is not subscriptable (tested)
TypeError: 'NoneType' object is not subscriptable (and its siblings — not iterable, not callable, no len()) all mean the same root problem as 'NoneType' object has no attribute: a variable you expected to hold a real value is None. The difference is which operation you tried on it — indexing with [], looping with for, or calling with () each produce their own distinct TypeError wording instead of AttributeError.
1. Eight operations, eight different messages
Python's error message depends on exactly which operation failed on None, not just that it failed:
Operation on None | Exact error (Python 3.13.5) |
|---|---|
x[0] | TypeError: 'NoneType' object is not subscriptable |
for i in x: | TypeError: 'NoneType' object is not iterable |
x() | TypeError: 'NoneType' object is not callable |
int(x) | TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType' |
len(x) | TypeError: object of type 'NoneType' has no len() |
5 + x | TypeError: unsupported operand type(s) for +: 'int' and 'NoneType' |
"a" in x | TypeError: argument of type 'NoneType' is not iterable |
All eight share one cause: something assigned None to a variable that the rest of the code assumes is a list, dict, string, number, or function.
2. "not subscriptable" means someone used [...] on a plain value
The most common single case: indexing the result of a function that forgot a return, or a dict lookup via .get() that didn't find a key:
>>> def no_return(): pass
>>> r = no_return()
>>> r[0]
TypeError: 'NoneType' object is not subscriptable
>>> x = None
>>> x[0]
TypeError: 'NoneType' object is not subscriptable
This is distinct from IndexError: list index out of range, which means you do have a real list, but asked for a position past its length. "not subscriptable" means you don't have a list (or dict, or anything supporting []) at all — you have None (or occasionally an int or other non-container type).
3. "not iterable" and "not callable" follow the same pattern
>>> x = None
>>> for i in x: pass
TypeError: 'NoneType' object is not iterable
>>> x()
TypeError: 'NoneType' object is not callable
"not callable" is a distinctive one worth knowing by sight: it almost always means a variable name shadowed a function. A classic example is accidentally reassigning a built-in or your own function name, like writing list = get_items() and later calling list() — except here list is now whatever get_items() returned, not the built-in.
4. Arithmetic and len() report the type pairing, not just "NoneType"
>>> 5 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> len(None)
TypeError: object of type 'NoneType' has no len()
>>> int(None)
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
These three are more verbose because they come from different code paths internally (operator overloading, the len() protocol, and type constructors), but the diagnosis is identical: a None ended up where a number, sized container, or convertible value was expected.
5. Where the None almost always comes from
- A function with a missing or conditional
return(see section 4 of the AttributeError guide linked above for the exact pattern). dict.get(key)on a missing key, then immediately indexing or iterating the result.- A database query or API call that returns
Nonefor "not found" instead of raising, then used without a check. - A default function argument of
None(def f(items=None):) used directly instead of being replaced with a real empty container first.
6. Fix checklist
- Check
if value is not None:before indexing, iterating, or calling it. - For the common
def f(items=None):pattern, replace the default early:if items is None: items = []. - Read the traceback's line number, then check the line above for where the value was assigned — same debugging approach as any
None-related error. - If the message says "not callable", specifically check for a variable that shadows a function name of the same spelling earlier in the same scope.
For the attribute-access sibling of this error family (.append(), .strip(), etc. instead of [], for, or ()), see AttributeError: 'NoneType' object has no attribute.
Frequently asked questions
What is the difference between 'not subscriptable' and IndexError?
'NoneType' object is not subscriptable means the variable isn't a list/dict/sequence at all - it's None, so [] doesn't apply. IndexError: list index out of range means you do have a real list, but the index you used is past its length. Different problems, different fixes.
Why does TypeError: 'NoneType' object is not callable happen?
It means code tried to call a variable with () as if it were a function, but the variable is actually None. The most common cause is a variable name that shadows a function - for example reassigning a variable to the result of calling the function, then calling that result again by the same name.
Why do int(None) and len(None) have longer error messages than x[0]?
They come from different internal mechanisms: int() goes through type conversion, len() goes through Python's length protocol, and both report what type combination failed rather than a short 'not X-able' phrase. The diagnosis is the same in all cases: a None value reached code expecting something else.
How is this related to AttributeError: 'NoneType' object has no attribute?
They're the same root cause (a None where a real value was expected) producing different exceptions depending on the operation: method/attribute access (.foo) raises AttributeError, while indexing ([]), iteration (for), and calling (()) raise TypeError with their own specific wording.
How do I find where a None value came from?
Read the traceback's line number and look at the assignment just above it - usually a function call, a dict.get(), or an API/database result. Split chained calls onto separate lines while debugging so each step has its own line number to blame.
Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5 on Linux using plain python3 one-liners. Every error below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python is free.