Debugging — Python Error Guide

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.

AttributeErrorException type
NoneTypeMost common culprit
PythonLanguage

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.

LearnBug — tracing where an object silently became None
🖼 Add a LearnBug screenshot here
What Causes It

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.

Silent None

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).

Misspelling

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.

Type confusion
Walkthrough

A dict.get() miss silently returns None

1

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.

users[1] = "Alex"
users[2] = "Sam"
users.get(99)no match
users.get(99) → None — no exception, just a None return
2

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 = Nonetype: NoneType
type(name) = NoneType — silently, no error raised here
3

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'

Code Example

The broken code, and the traceback it produces

PythonBroken — .get() returns None on a miss
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 here
TracebackWhat Python actually prints
Traceback (most recent call last):
  File "users.py", line 5, in <module>
    print(name.upper())
               ^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'upper'
The Fix

Check for None before using the value

PythonFixed — guard against None explicitly
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

Error classAttributeErrorRaised when an object's type doesn't define the accessed attribute/method
Typical causeUnexpected NoneA function or lookup silently returned None instead of raising or the expected value
Fix patternif x is not None:Check before using, right after the call that might return None
Debugging tipprint(type(x))When unsure, check the actual runtime type before assuming what methods are available

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.

Open Playground →