Engineering6 min read

Fix NameError in Python: "name 'X' is not defined" — 6 Causes and Fixes

Python NameError means the interpreter hit a name it doesn't recognize. Here are the 6 most common causes — typos, scope, missing imports — and the exact fix for each one.

PythonNameErrordebuggingerror fixVS Code

What Is a NameError?

Python raises NameError when it encounters a name — variable, function, or class — that hasn't been defined in the current scope.

Error: NameError: name 'user_data' is not defined

This error always means one of six things. Work through each cause below in order — most NameErrors are fixed by cause 1 or 2.

Cause 1: Typo in Variable Name

Python is case-sensitive. UserData, user_data, and userdata are three different names. A single character difference causes NameError.

python
# ❌ Defined as user_data, referenced as userdata
user_data = fetch_user(user_id)
print(userdata['email'])  # NameError: name 'userdata' is not defined

▎ Fix: Use your editor's "Go to Definition" (F12 in VS Code) on the erroring name. If it can't navigate, the name doesn't exist — check spelling
▎ against where it was defined.

# ✅ Names match
user_data = fetch_user(user_id)
print(user_data['email'])

Cause 2: Variable Used Before Assignment

Python executes top to bottom. Referencing a variable before the line that assigns it causes NameError.

# ❌ result used before it's assigned
def calculate_total(items):
    print(f"Total: {result}")  # NameError here
    result = sum(item['price'] for item in items)
    return result

▎ Fix: Move the reference after the assignment, or initialize the variable at the top of the function.

# ✅ Initialize first
def calculate_total(items):
    result = sum(item['price'] for item in items)
    print(f"Total: {result}")
    return result

Cause 3: Variable Defined Inside a Conditional That Didn't Run

Variables assigned inside if blocks only exist if that branch executed. Referencing them outside is NameError waiting to happen.

# ❌ user only defined if API call succeeds
def get_username(user_id):
    if user_id:
        user = api.get_user(user_id)
    return user.name  # NameError if user_id was falsy

▎ Fix: Initialize the variable before the conditional with a sensible default.

# ✅ Always defined
def get_username(user_id):
    user = None
    if user_id:
        user = api.get_user(user_id)
    return user.name if user else 'Anonymous'

Cause 4: Scope Error — Variable Defined in Different Function

Variables defined inside a function are local to that function. They don't exist in other functions or at module level.

# ❌ config defined inside setup(), referenced outside
def setup():
    config = load_config()

def run():
    print(config['debug'])  # NameError: config is not defined

setup()
run()

▎ Fix: Return the value and pass it where needed, or use a module-level variable.

# ✅ Pass through return value
def setup():
    return load_config()

def run(config):
    print(config['debug'])

config = setup()
run(config)

▎ Note: Using global to fix scope issues is a code smell. If you find yourself reaching for global, the function design needs refactoring — not a
▎ global variable.

Cause 5: Missing Import

Built-in modules (json, os, datetime) and third-party packages must be imported before use. Referencing them without importing raises NameError,
not ImportError.

# ❌ datetime used without import
def get_timestamp():
    return datetime.now().isoformat()  # NameError: name 'datetime' is not defined

▎ Fix: Add the import at the top of the file.

# ✅ Import first
from datetime import datetime

def get_timestamp():
    return datetime.now().isoformat()

▎ Tip: VS Code with Pylance auto-detects missing imports. Hover over the red underline → "Quick Fix""Add import". Faster than typing it
▎ manually.

Cause 6: Name Defined in a Try Block, Used After

When an exception occurs inside a try block, assignment after the error point doesn't happen. Code after the try/except can reference a name that
was never set.

# ❌ connection only assigned if try succeeds
try:
    connection = db.connect(DATABASE_URL)
    cursor = connection.cursor()
except Exception as e:
    print(f"DB error: {e}")

cursor.execute("SELECT * FROM users")  # NameError if connect() failed

▎ Fix: Initialize variables before the try block, or move usage inside the try.

# ✅ Use inside try where it's guaranteed to exist
try:
    connection = db.connect(DATABASE_URL)
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM users")
    return cursor.fetchall()
except Exception as e:
    print(f"DB error: {e}")
    return []

How to Find It Fast

Python's NameError stack trace points to the exact line. Read it bottom-up:

Traceback (most recent call last):
  File "app.py", line 47, in process_order
    total = calculate_discount(subtotal, promo_cide)
NameError: name 'promo_cide' is not defined. Did you mean: 'promo_code'?

Python 3.10+ includes "Did you mean?" suggestions. If you see that — it's a typo (Cause 1). Fix the name and move on.

For cross-file or cross-scope NameErrors, paste the error + surrounding function into DebugAI. It reads your imports, your function definitions,
and your call sites — and identifies whether the name was never defined, defined in wrong scope, or imported incorrectly.

Quick Reference

┌──────────────────────┬──────────────────────────────────────────┬──────────────────────────────────┐
│        Cause         │                 Symptom                  │               Fix                │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Typo                 │ Name looks almost right                  │ Check spelling, case sensitivity │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Used before assigned │ Error on first reference                 │ Move reference after assignment  │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Conditional scope    │ Error only on some inputs                │ Initialize before if block       │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Function scope       │ Error referencing another function's var │ Return and pass as argument      │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Missing import       │ Standard library or package name         │ Add import at file top           │
├──────────────────────┼──────────────────────────────────────────┼──────────────────────────────────┤
│ Try block scope      │ Error after try/except                   │ Move usage inside try            │
└──────────────────────┴──────────────────────────────────────────┴──────────────────────────────────┘

Fix NameErrors once and prevent them permanently: enable Pylance strict mode in VS Code ("python.analysis.typeCheckingMode": "strict"). It catches
 undefined names before you run the code.

Debug faster starting today.

Free VS Code extension. 10 sessions/day. No credit card.

Install Free →

Related Posts

Engineering

How to Debug a Next.js Application in VS Code (App Router Guide)

8 min read

Engineering

Fix FastAPI 422 Unprocessable Entity — 5 Causes With Code

7 min read

← All posts