Undefined Variable

Debug undefined variable errors

3 min read 622 words

DebugUndefinedErrorexceptions.

The Error

UndefinedError: Undefined variable 'usre' in page.html:5

Common Causes

Solutions

Use default Filter

{{ user.nickname | default("Anonymous") }}
{{ config.timeout | default(30) }}

Check with is defined

Theis defined test works on attribute chains, not just top-level variables. If any part of the chain is missing, the result is undefined:

{% if user is defined %}
    {{ user.name }}
{% else %}
    Guest
{% end %}

Attribute Chains

{# Checks if pokemon has a "name" attribute — not just if pokemon exists #}
{% if pokemon.name is defined %}
    {{ pokemon.name }}
{% end %}

{# Works with dict keys too #}
{% if settings.theme is defined %}
    Theme: {{ settings.theme }}
{% end %}

{# Deep chains #}
{% if page.author.avatar is defined %}
    <img src="{{ page.author.avatar }}">
{% end %}

Undefined Sentinel

Missing attribute access returns an_Undefinedsentinel (not an empty string). The sentinel is:

  • Falsy{% if pokemon.name %}works as a guard
  • Stringifies to""{{ pokemon.name }}renders nothing when undefined
  • Iterable — yields nothing, so{% for x in missing_attr %}produces no output

Theis defined and is undefined tests work correctly on attribute chains (e.g. {% if pokemon.name is defined %}), making intent explicit. See Tests Reference for the full test list.

Optional Chaining Pattern

{% if post and post.author %}
    {{ post.author.name }}
{% end %}

Safe Navigation

{{ user | default({}) | attr("name") | default("Unknown") }}

Debug Tips

# In Python
print(context.keys())

Use debug Filter

{{ user | debug }}

Output (to stderr):

DEBUG: <User>
  .name = 'Alice'
  .email = 'alice@example.com'

Check Template Context

def render_debug(template_name, **context):
    print(f"Rendering {template_name}")
    print(f"Context keys: {list(context.keys())}")
    return env.render(template_name, **context)

Strict Undefined Mode

Enablestrict_undefined=Trueon your Environment to catch attribute typos immediately instead of getting silent empty output:

env = Environment(
    loader=FileSystemLoader("templates/"),
    strict_undefined=True,
)

With strict mode, {{ user.typo }} raises UndefinedErrorimmediately with a descriptive message ("Undefined attribute 'typo'") instead of rendering as an empty string. Error messages distinguish between variable, attribute, and key lookups.

This is recommended for development and CI. In production, you may prefer the lenient default to avoid breaking pages on missing data.

Prevention

Type Hints for Context

from dataclasses import dataclass

@dataclass
class PageContext:
    title: str
    user: User
    items: list[Item]

# IDE will catch missing fields
context = PageContext(title="Hello", user=user, items=items)
template.render(**asdict(context))

Template Validation

def validate_context(context, required):
    missing = [k for k in required if k not in context]
    if missing:
        raise ValueError(f"Missing: {missing}")

See Also