AttributeError —
That method doesn't exist on this type.
You called a method or accessed an attribute that the object's actual type doesn't have — and the single most common cause is that the object is None when you expected something else. Watch the attribute lookup fail on LearnBug and see exactly what type the object actually turned out to be.
What is AttributeError?
Python raises this when you access obj.something and the object's type doesn't define something as a method or attribute. It's not about the object's value — it's specifically about whether that type supports the operation at all.
Why visualization helps
The traceback names the missing attribute, but the real question is almost always "why is this object the wrong type?" — usually it's silently None from a few lines earlier. LearnBug shows each variable's actual type and value as execution proceeds, so you can trace exactly where an object became None instead of what you expected.
Three ways an attribute lookup fails
A function silently returned None
A function without an explicit return for every path (or one using .get() / a search that finds nothing) returns None — and None has almost no methods.
Typo in the method name
Calling .appned() instead of .append(), or confusing similarly-named methods between types (like a list's vs a string's methods).
Wrong assumed type
Treating a string as if it were a list (or vice versa) — some method names overlap between types, but not all, and this surfaces the mismatch.
A dict.get() miss silently returns None
find_user(99) looks up users.get(99) — 99 isn't in the dictionary
The dictionary only has entries for user IDs 1 and 2. .get() is designed to return None instead of raising when the key is missing — which is convenient here, but only if the caller checks for it.
name = find_user(99) — name is now None, not a string
Nothing about this line looks wrong on its own. name is a perfectly valid variable holding a perfectly valid value — it's just not the type the next line assumes.
name.upper() — None has no .upper() method, AttributeError
Strings have .upper(); NoneType does not. Python checks the actual runtime type of name, finds it's None, and has nothing matching .upper to call.
Result: AttributeError: 'NoneType' object has no attribute 'upper' ✗
The broken code, and the traceback it produces
def find_user(user_id):
users = {1: "Alex", 2: "Sam"}
return users.get(user_id) # returns None if not found
name = find_user(99)
print(name.upper()) # name is None hereTraceback (most recent call last):
File "users.py", line 5, in <module>
print(name.upper())
^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'upper'Check for None before using the value
def find_user(user_id):
users = {1: "Alex", 2: "Sam"}
return users.get(user_id)
name = find_user(99)
if name is not None:
print(name.upper())
else:
print("User not found")Quick Reference
Frequently asked questions
Why is None specifically the most common cause?
Because so many operations in Python return None on a "no result" path without raising an exception — dict.get() on a miss, a function falling off the end without an explicit return, re.match() finding no match. None then flows silently through your program until it hits code that assumes a real object, and .upper(), .append(), and similar calls are where that assumption finally breaks.
How do I quickly figure out what type an object actually is?
Add a temporary print(type(obj)) right before the failing line, or use LearnBug's step-by-step execution to watch the type directly. Once you know the actual type, the fix is usually obvious — either handle that type's real interface, or fix why it's not the type you expected.
Is there a way to avoid checking for None everywhere?
For functions you control, prefer raising an explicit exception or returning a sensible default over returning None silently — that pushes the failure to happen immediately and loudly, rather than several lines later at an unrelated attribute access. Type hints (-> str | None) also help tools flag missing None-checks before you even run the code.
What's the difference between AttributeError and TypeError here?
AttributeError means the object's type simply doesn't have that method or attribute defined at all. TypeError is broader — it covers any operation (including method calls with wrong argument types) that doesn't fit the expected type contract. A missing method specifically is always AttributeError, not TypeError.
Watch an object's type at every step
Paste your code into LearnBug and trace exactly where None sneaked in.