AttributeError: 'NoneType' object has no attribute (tested)

AttributeError: 'NoneType' object has no attribute 'X' means a variable you expected to hold a real object is actually None, and you then called .X on it. Python never guesses what you meant; it fails exactly where the bad call happens, which is usually a line or two after where the value became None. We reproduced the six most common causes on a real interpreter and captured each exact traceback.

1. The error, piece by piece

'NoneType' object has no attribute 'append' tells you two things: the object on the left of the dot is None (its type is NoneType), and you tried to use .append on it, which only lists have. The fix is never to patch the attribute call — it is to find why the variable is None in the first place.

2. Six reproduced causes

Code patternExact error (Python 3.13.5)
y = x.append(4); y.append(5)AttributeError: 'NoneType' object has no attribute 'append'
v = d.get("missing"); v.lower()AttributeError: 'NoneType' object has no attribute 'lower'
m = re.match(r"\d+", "abc"); m.group()AttributeError: 'NoneType' object has no attribute 'group'
r = helper(); r.split(",") (helper has no return)AttributeError: 'NoneType' object has no attribute 'split'
r = maybe("abc"); r.replace("a","b") (maybe only returns on one branch)AttributeError: 'NoneType' object has no attribute 'replace'
d.get("name").strip() (chained, key missing)AttributeError: 'NoneType' object has no attribute 'strip'

All six share one root cause: a value that the code assumed was a string, list, or match object turned out to be None.

3. Cause 1: in-place list/dict methods return None

list.append(), list.sort(), dict.update(), and set.add() all mutate the object and return None — on purpose, as a signal they are in-place operations. Assigning their result is the bug:

>>> x = [1, 2, 3]
>>> y = x.append(4)   # y is None, x is now [1, 2, 3, 4]
>>> y.append(5)
AttributeError: 'NoneType' object has no attribute 'append'

Fix: don't assign the result. Use x.append(4) on its own line, then use x.

4. Cause 2: dict.get() with a missing key

dict.get(key) returns None (not an exception) when the key is absent — that is its whole point versus d[key], which raises KeyError instead. Calling a string method on the result assumes the key always exists:

>>> d = {"a": 1}
>>> v = d.get("b")
>>> v.lower()
AttributeError: 'NoneType' object has no attribute 'lower'

Fix: give .get() a default, or check first: d.get("b", "").lower() or if v is not None: v.lower().

5. Cause 3: re.match / re.search with no match

Both return None when the pattern doesn't match — they never raise. Calling .group() straight away is the most common regex bug in Python:

>>> import re
>>> m = re.match(r"\d+", "abc")
>>> m.group()
AttributeError: 'NoneType' object has no attribute 'group'

Fix: if m: m.group(), or use the walrus operator: if (m := re.match(r"\d+", s)): m.group().

6. Cause 4: a function with a missing or conditional return

A Python function with no return statement, or one that only returns inside an if, implicitly returns None on the paths that fall through. The traceback points at the call site, not the function definition, which is what makes this cause confusing to spot:

>>> def helper():
...     pass   # no return -> None
>>> r = helper()
>>> r.split(",")
AttributeError: 'NoneType' object has no attribute 'split'

>>> def maybe(s):
...     if s.startswith("x"):
...         return s
...     # falls through to None if condition is False
>>> r = maybe("abc")
>>> r.replace("a", "b")
AttributeError: 'NoneType' object has no attribute 'replace'

Fix: add an explicit return (or return None plus a caller check) on every code path, especially the "else" case you didn't think you needed.

7. Cause 5: chaining calls on a one-liner

Chaining hides the intermediate None so there is no line to put a breakpoint on:

>>> d = {}
>>> d.get("name").strip()
AttributeError: 'NoneType' object has no attribute 'strip'

Fix: split the chain into two lines while debugging (name = d.get("name"); name.strip()) so the traceback's line number tells you exactly which call returned None.

8. General fix checklist

The JavaScript equivalent of this mistake is Cannot read properties of undefined — same root cause (reading a property off a missing value), different language's spelling of it. For the "wrong type entirely" sibling error, see ModuleNotFoundError vs ImportError.

Frequently asked questions

What does 'NoneType' object has no attribute mean?

It means a variable that your code expected to be a string, list, dict, or other object is actually Python's None value, and you called a method or accessed an attribute on it. None has no methods like .append, .strip, or .group, so Python raises AttributeError.

Why does dict.get() return None instead of raising an error?

That is get()'s designed behavior: d.get(key) returns None (or a default you supply) when the key is missing, instead of raising KeyError like d[key] does. It is meant for optional lookups, so you must handle the None case yourself.

Why did my function return None when I wrote a return statement?

Usually because the return is inside an if block and the condition was False on that call, so execution fell through to the end of the function, which implicitly returns None. Add an explicit return (or else branch) for every path.

How do I find where the None came from?

Read the traceback's line number, then look at the assignment just above it. Split chained calls (like d.get('x').strip()) onto separate lines while debugging so each step has its own line number.

Does list.append() return the updated list?

No. append(), sort(), extend(), and dict.update() all mutate the object in place and return None. Use the original variable after calling them; never assign their result.

Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5 on Linux using plain python3 one-liners and small scripts under /tmp. Every traceback below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Python is free.