Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Ansible By James Joyner IV · · 9 min read

Ansible Error Guide: 'AnsibleUndefinedVariable' Exception During Task Execution

Fix Ansible's 'An exception occurred during task execution ... AnsibleUndefinedVariable' error: diagnose missing vars, scoping, typos, and unset facts in playbooks.

  • #ansible
  • #troubleshooting
  • #errors
  • #variables

Exact Error Message

fatal: [db-01]: FAILED! => {
    "changed": false,
    "msg": "An exception occurred during task execution. To see the full traceback, use -vvv. The error was: 'db_password' is undefined. 'db_password' is undefined"
}

You may also see the variant with the full class name:

"msg": "AnsibleUndefinedVariable: 'dict object' has no attribute 'db_password'"

Both point at the same root problem: a variable referenced in a task, template, or expression has no value at the moment Ansible tried to use it.

What the Error Means

When Ansible renders a task it resolves every {{ variable }} reference. If a referenced name is not defined anywhere in scope at that point in the play, Jinja2’s strict-undefined behavior raises AnsibleUndefinedVariable. Ansible wraps it as An exception occurred during task execution.

By default Ansible treats undefined variables as fatal (error_on_undefined_vars is on). This is intentional: silently substituting an empty string into a password, path, or hostname is far more dangerous than failing loudly.

Common Causes

  • A typo in the variable name (db_passwd vs db_password).
  • The variable lives in a vars_file, group_vars, or host_vars that was never loaded for this host or group.
  • A fact that has not been gathered yet (gather_facts: false) but is referenced anyway.
  • Variable scoping: a set_fact ran on one host but the variable is read on another, or a block/role local was used outside its scope.
  • registered results referenced before the registering task ran (or after it was skipped by when).
  • A nested key that does not exist on a dict, surfacing as 'dict object' has no attribute '...'.

How to Reproduce the Error

Reference a variable you never define:

- hosts: db
  gather_facts: false
  tasks:
    - name: Configure database
      ansible.builtin.debug:
        msg: "Connecting as {{ db_user }} with {{ db_password }}"
ansible-playbook db.yml -i inventory.ini --check --diff -vvv
fatal: [db-01]: FAILED! => {"changed": false, "msg": "An exception occurred during task execution. ... The error was: 'db_password' is undefined."}

A skipped-register variant: a task guarded by when: false never runs, then a later task reads its registered result and fails the same way.

Diagnostic Commands

Run with -vvv in check mode to get the full traceback and the exact undefined name:

ansible-playbook db.yml -i inventory.ini --check --diff -vvv

Dump everything Ansible knows about the host to see which vars are actually present:

ansible db-01 -i inventory.ini -m setup

Confirm what inventory-level variables resolve for the host and group:

ansible-inventory -i inventory.ini --host db-01

Check a single variable’s value quickly with debug:

ansible db-01 -i inventory.ini -m debug -a "var=db_password"

Step-by-Step Resolution

  1. Read the exact undefined name. The error names the variable (or the missing attribute). Confirm spelling against where you think it is defined.

  2. Find where it should be defined. Search your tree:

grep -rn "db_password" group_vars/ host_vars/ vars/ roles/
  1. Make sure the file is actually loaded. group_vars/db.yml only loads for hosts in the db group. Verify membership:
ansible-inventory -i inventory.ini --graph
  1. Gather facts if you reference them. If a task uses ansible_default_ipv4 or similar, ensure gather_facts: true or add an explicit setup task.

  2. Guard genuinely optional variables with a default so absence is intentional rather than fatal:

msg: "Connecting as {{ db_user | default('postgres') }}"
  1. Fix register/scope issues. Ensure the registering task is not skipped, or test for it:
when: result is defined and result.rc == 0
  1. Re-run in check mode and confirm the variable resolves before applying:
ansible-playbook db.yml -i inventory.ini --check --diff

Prevention and Best Practices

  • Define required variables in group_vars/host_vars and document them in the role’s defaults/main.yml so there is always a sensible fallback.
  • Use | default(...) only for truly optional values; for required secrets, prefer failing loudly with assert.
  • Validate inputs early with a fail-fast assert block at the top of a role:
- ansible.builtin.assert:
    that: db_password is defined
    fail_msg: "db_password must be set"
  • Keep variable names consistent and namespaced per role (myapp_db_password) to avoid collisions and typos.
  • Do not reference facts when gather_facts: false; gather explicitly or supply the value.
  • Lint with ansible-lint, which flags many undefined-variable patterns before runtime.
  • template error while templating string — a Jinja2 syntax/evaluation error, not a missing variable.
  • 'dict object' has no attribute '...' — the variable exists but the nested key you indexed does not.
  • The conditional check '...' failed — a when: expression referencing an undefined variable.
  • VARIABLE IS NOT DEFINED! — what debug prints when you var= an undefined name, rather than a fatal error.

Frequently Asked Questions

Why does Ansible fail instead of using an empty value? error_on_undefined_vars defaults to true precisely so that an undefined password or path causes a loud failure instead of silently breaking your config. Leave it on.

My variable is in group_vars but still undefined. The host is probably not a member of that group. Check with ansible-inventory --graph and confirm the file name matches the group name.

How do I make a variable optional? Wrap each reference in {{ var | default('fallback') }}. For required values, use an assert so the run fails with a clear message instead of a cryptic traceback.

A registered variable is undefined. The task that should register it was skipped by a when: condition or never ran. Guard downstream usage with when: result is defined. For more variable and scoping patterns, see the Ansible guides.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.