
This AttributeError NoneType append is a classic combination of two common problems: a NoneType error and a List method error.
It means: You are trying to use the .append() method, but the variable you’re using it on is None, not a list.
⚡ Quick Fix: AttributeError: ‘NoneType’ object has no attribute ‘append’ — Python Missing return Statement and In-Place Method Assignment Fix for List Building
Your variable holds None instead of a list — a function returned nothing on one of its code paths, and .append() has no list to attach to.
# WRONG — function returns None when user_id is 5 or below
def get_user_scores(user_id):
if user_id > 10:
return [90, 85, 100]
else:
return None # None reaches the caller silently
scores = get_user_scores(5)
scores.append(40) # AttributeError: 'NoneType' object has no attribute 'append'
# WRONG — .append() modifies in-place and returns None, assigning it kills the list
my_list = [1, 2, 3]
my_list = my_list.append(4) # my_list is now None
my_list.append(5) # AttributeError fires here
# RIGHT — always return [] instead of None when a list is expected
def get_user_scores(user_id):
if user_id > 10:
return [90, 85, 100]
return [] # empty list is safe to .append() on
scores = get_user_scores(5)
scores.append(40)
print(scores) # Output: [40]
# RIGHT — call .append() as a standalone statement, never assign its result
my_list = [1, 2, 3]
my_list.append(4) # modifies my_list directly
print(my_list) # Output: [1, 2, 3, 4]The two causes below explain exactly how None ends up where your list should be — trace it back to the source, not the crash line.
The Cause
This almost always happens when you call a function that was supposed to return a list, but it failed or had a code path that returned None instead.
Problem Code:
def get_user_scores(user_id):
if user_id > 10:
return [90, 85, 100]
else:
# This user has no scores, so we return nothing
return None
# 1. This works fine
high_scorer_list = get_user_scores(20)
high_scorer_list.append(99) # Appends to [90, 85, 100]
# 2. This crashes
low_scorer_list = get_user_scores(5) # This variable is now None
low_scorer_list.append(40)
# CRASH! AttributeError: 'NoneType' object has no attribute 'append'The Fix: Always Return an Iterable (e.g., [])
The best fix is to make your function “safer.” A function that “gets a list” should always return a list, even if it’s an empty one.
Corrected Function:
def get_user_scores(user_id):
if user_id > 10:
return [90, 85, 100]
else:
# THE FIX: Return an empty list
return []Now, the code will run without crashing:
low_scorer_list = get_user_scores(5) # This variable is now [] low_scorer_list.append(40) print(low_scorer_list) # Output: [40]
AttributeError: ‘NoneType’ object has no attribute ‘append’ — Two Sources of None, One Rule That Prevents Both
AttributeError: ‘NoneType’ object has no attribute ‘append’ fires at the .append() call — but the bug lives at the assignment that handed None to your variable. Fix the source, not the crash line.
Run print(type(your_variable)) directly above the .append() call. If it prints , trace the variable back through your code to the assignment that produced it.
Two sources generate None silently and cause this exact error.
A function with an incomplete return path. A function that returns a list on the happy path and returns None — explicitly or implicitly — on any other branch hands None to every caller that hits that branch. The fix is consistent return types: return [] on the no-data path, return [items] on the data path. Never let a function that callers treat as a list source return None on any branch.
def get_scores(user_id: int) -> list:
if user_id > 10:
return [90, 85, 100]
return [] # consistent — always a list, never None
The -> list type annotation enforces this at the function signature level. Type checkers like mypy flag any return path that hands back None when the annotation promises a list.
.append() assigned to a variable. my_list = my_list.append(4) overwrites my_list with None in one line. .append(), .extend(), .insert(), .remove(), .sort(), and .reverse() all return None — they modify the original list directly. Call every one of these as a standalone statement. If you need the modified list assigned to a new variable, use a list comprehension or slicing instead.
Safe list copy with modification
new_list = my_list + [4] # creates a new list — my_list untouched
new_list = [*my_list, 4] # unpacking alternative — same result





