Skip to content

Fix: Python AttributeError: 'NoneType' object has no attribute

FixDevs ·

Quick Answer

How to fix Python AttributeError NoneType object has no attribute caused by functions returning None, method chaining, failed lookups, uninitialized variables, and missing return statements.

The Error

You run your Python script and get:

Traceback (most recent call last):
  File "app.py", line 12, in <module>
    print(result.name)
          ^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'name'

Or variations like:

AttributeError: 'NoneType' object has no attribute 'append'
AttributeError: 'NoneType' object has no attribute 'split'
AttributeError: 'NoneType' object has no attribute 'get'

The attribute name changes, but the pattern is the same: you tried to access a property or call a method on something that is None. Python does not know what .name, .append(), or .split() means on None because None has no attributes.

Why This Happens

In Python, None is a special object that represents the absence of a value. When a variable holds None and you try to access an attribute on it, Python raises AttributeError.

The critical question is: why is the variable None in the first place? Here are the most common causes:

  • A function returned None implicitly. Python functions that don’t have a return statement (or have a bare return) return None by default.
  • A list method returned None. Methods like .sort(), .append(), .reverse(), and .extend() modify the list in place and return None.
  • A dictionary lookup returned None. dict.get() returns None when the key is not found (unless you provide a default).
  • A failed search returned None. re.match(), re.search(), and list.find() equivalents return None when there is no match.
  • A variable was never assigned. You declared a variable but never gave it a value, or a conditional branch skipped the assignment.
  • Method chaining on a mutating method. Calling .sort().reverse() fails because .sort() returns None.

Fix 1: Check Functions That Return None Implicitly

The most common cause. A function without an explicit return statement returns None:

def find_user(users, name):
    for user in users:
        if user["name"] == name:
            return user
    # No return here — returns None if user not found

result = find_user(users, "Alice")
print(result.name)  # AttributeError if Alice is not in the list

Fix: Always handle the case where the function returns None:

result = find_user(users, "Alice")
if result is not None:
    print(result["name"])
else:
    print("User not found")

Or make the function raise an exception instead of returning None:

def find_user(users, name):
    for user in users:
        if user["name"] == name:
            return user
    raise ValueError(f"User '{name}' not found")

Pro Tip: Use type hints to make None returns explicit. def find_user(...) -> dict | None: tells both the developer and tools like mypy that the function can return None. This catches the error before you even run the code.

Fix 2: Don’t Chain Methods That Return None

List methods that modify in place return None. Chaining them is a classic Python trap:

# WRONG — .sort() returns None
sorted_names = names.sort()
print(sorted_names.reverse())  # AttributeError: 'NoneType' has no attribute 'reverse'
# WRONG — .append() returns None
result = my_list.append("item")
print(result.count("item"))  # AttributeError

Fix: Call mutating methods on separate lines:

names.sort()
names.reverse()
print(names)

Or use the non-mutating alternatives that return a new object:

sorted_names = sorted(names)          # Returns new list
reversed_names = list(reversed(names)) # Returns new list

Methods that modify in place and return None:

MethodReturnsAlternative
list.sort()Nonesorted(list)
list.append(x)Nonelist + [x]
list.extend(x)Nonelist + x
list.reverse()Nonelist[::-1] or reversed(list)
list.insert(i, x)None
dict.update(x)None{**dict, **x}
set.add(x)None

This is closely related to the NoneType not subscriptable error, which occurs when you try to index None with [] instead of accessing an attribute with ..

Fix 3: Handle dict.get() and Missing Keys

dict.get() returns None when the key doesn’t exist:

config = {"host": "localhost", "port": 3306}

db_name = config.get("database")
print(db_name.upper())  # AttributeError: 'NoneType' has no attribute 'upper'

Fix: Provide a default value:

db_name = config.get("database", "mydb")
print(db_name.upper())  # Works — defaults to "mydb"

Or check before using:

db_name = config.get("database")
if db_name:
    print(db_name.upper())

If the key must exist and its absence is an error, use direct access:

db_name = config["database"]  # Raises KeyError if missing — better than a silent None

Fix 4: Handle None from re.match() and re.search()

Regex functions return None when there is no match:

import re

text = "no numbers here"
match = re.search(r'\d+', text)
print(match.group())  # AttributeError: 'NoneType' has no attribute 'group'

Fix: Check the match before accessing groups:

match = re.search(r'\d+', text)
if match:
    print(match.group())
else:
    print("No match found")

Or use the walrus operator (Python 3.8+):

if match := re.search(r'\d+', text):
    print(match.group())

Fix 5: Fix Uninitialized Variables and Conditional Assignments

A variable might be None because a conditional branch never assigned it:

def get_discount(user_type):
    if user_type == "premium":
        discount = 0.2
    elif user_type == "member":
        discount = 0.1
    # No else — discount is undefined for other types

    return discount  # UnboundLocalError or None if initialized earlier

Fix: Always provide a default value:

def get_discount(user_type):
    discount = 0.0  # Default
    if user_type == "premium":
        discount = 0.2
    elif user_type == "member":
        discount = 0.1
    return discount

Fix 6: Fix Class init and Missing Returns

If __init__ accidentally returns something, or a class method forgets to return, you get None:

class UserService:
    def get_user(self, user_id):
        user = self.db.query(user_id)
        # Forgot to return user!

service = UserService()
user = service.get_user(123)
print(user.name)  # AttributeError: 'NoneType' has no attribute 'name'

Fix: Add the return statement:

def get_user(self, user_id):
    user = self.db.query(user_id)
    return user  # Don't forget this!

Common Mistake: In Python, __init__ must not return a value. If you try return something in __init__, Python raises TypeError. But forgetting return in other methods is the most common cause of this error in class-based code.

Fix 7: Handle API and Database Responses

External data sources can return None unexpectedly:

import requests

response = requests.get("https://api.example.com/user/123")
data = response.json()

# The API might return {"user": null}
user = data.get("user")
print(user["name"])  # AttributeError if user is None

Fix: Validate the response before using it:

user = data.get("user")
if user is None:
    raise ValueError("API returned no user data")
print(user["name"])

For database ORMs:

# SQLAlchemy
user = session.query(User).filter_by(id=123).first()  # Returns None if not found
if user is None:
    raise ValueError("User not found")
print(user.name)

Fix 8: Debug with print() and type()

When you cannot figure out why a variable is None, add debug prints:

result = some_function()
print(f"result = {result}")
print(f"type = {type(result)}")

# If result is None, trace back to some_function

Check every step in a chain:

a = step_one()
print(f"after step_one: {a} (type: {type(a)})")

b = a.step_two()
print(f"after step_two: {b} (type: {type(b)})")

c = b.step_three()  # If b is None, this is where it crashes

Use Python’s traceback module for more detail:

import traceback

try:
    result.name
except AttributeError:
    traceback.print_exc()
    print(f"result was: {result!r}")

If your debugging reveals an import issue rather than a None value, check fixing ModuleNotFoundError or circular import errors.

Fix 9: Use Type Hints and mypy

Type hints catch None attribute access at development time:

from typing import Optional

def find_user(name: str) -> Optional[dict]:
    # Returns dict or None
    ...

result = find_user("Alice")
print(result.name)  # mypy flags this: Item "None" of "Optional[dict]" has no attribute "name"

Run mypy to catch these before runtime:

pip install mypy
mypy your_script.py

Modern Python (3.10+) uses dict | None instead of Optional[dict]:

def find_user(name: str) -> dict | None:
    ...

Still Not Working?

If you have checked all the fixes above and still get this error:

Check for monkey-patching. Something might be overwriting a variable or attribute with None at runtime. Search your codebase for assignments to the variable in question.

Check for thread safety. In multithreaded code, one thread might set a value to None while another thread tries to access its attributes. Use locks or thread-safe data structures.

Check decorator return values. A decorator that forgets to return the wrapped function effectively replaces the function with None:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("before")
        func(*args, **kwargs)
        # Missing: return func(*args, **kwargs)
    # Missing: return wrapper

@my_decorator
def my_function():
    return "hello"

my_function()  # TypeError or AttributeError — my_function is None

Fix both return statements in the decorator.

Check for property setters. A @property that returns None implicitly causes this error when you access nested attributes on the property value. This behaves the same as TypeError: cannot read properties of undefined in JavaScript — both errors stem from accessing attributes on an empty value.

Check for circular imports causing partial initialization. If module A imports from module B, and module B imports from module A, some variables in the modules may be None during initialization. See fixing Python circular imports.

Use assertions during development. Add assert statements to catch None values early:

result = find_user("Alice")
assert result is not None, "find_user returned None — user not found"
print(result.name)

Assertions are removed when Python runs with -O (optimize) flag, so they don’t affect production performance.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles