AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Fix Undefined Variable Error: Complete Troubleshooting Guide

By Luca Berton · Published 2024-01-01 · Category: installation

Fix Ansible undefined variable errors. Use default filter, debug variable scope, handle missing facts, and prevent undefined variable issues in playbooks.

Ansible Fix Undefined Variable Error: Complete Troubleshooting Guide

Introduction

Today we're going to talk about Ansible troubleshooting, specifically about the undefined variable errors. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible Fix 'VARIABLE IS NOT DEFINED' Error: Undefined Variables

Playbook

The best way of talking about Ansible troubleshooting is to jump in a live Playbook to show you practically the undefined variable error and how to solve it!

error code

• underfinedvariable_error.yml
---
- name: debug module Playbook
  hosts: all
  tasks:
    - name: debug message
      ansible.builtin.debug:
        msg: "{{ fruit }}"

error execution

$ ansible-playbook troubleshooting/undefinedvariable_error.yml

PLAY [file module demo] ***************************************************************************

TASK [Gathering Facts] **************************************************************************** ok: [demo.example.com]

TASK [debug message] ****************************************************************************** fatal: [demo.example.com]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'fruit' is undefined\n\nThe error appears to be in '/Users/lberton/prj/github/ansible-pilot/troubleshooting/undefinedvariable_error.yml': line 5, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: debug message\n ^ here\n"}

PLAY RECAP **************************************************************************************** demo.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

fix code

• underfinedvariable_fix.yml
---
- name: debug module Playbook
  hosts: all
  vars:
    fruit: "apple"
  tasks:
    - name: debug message
      ansible.builtin.debug:
        msg: "{{ fruit }}"

fix execution

$ ansible-playbook troubleshooting/undefinedvariable_fix.yml

PLAY [debug module Playbook] **************************************************************************

TASK [Gathering Facts] **************************************************************************** ok: [demo.example.com]

TASK [debug message] ****************************************************************************** ok: [demo.example.com] => { "msg": "apple" }

PLAY RECAP **************************************************************************************** demo.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

code with ❤️ in GitHub

Conclusion

Now you know how to troubleshoot the most common Ansible undefined variable error.

See also: Ansible troubleshooting - AWS Failed to import the required Python library (botocore or boto3)

Why Variables Become Undefined

Typo in variable name — most common cause Variable defined in wrong scope — defined in one play/role but used in another Missing vars: section — forgot to define the variable Conditional variable — variable only exists when a previous task ran Missing role defaults — expected defaults/main.yml to provide a value

Fix Strategies

Strategy 1: Define the variable

---
- name: Define variables properly
  hosts: all
  vars:
    fruit: "apple"
    color: "red"
  tasks:
    - name: use the variable
      ansible.builtin.debug:
        msg: "The {{ fruit }} is {{ color }}"

Strategy 2: Use the default() filter

The safest approach for optional variables:

- name: Safe variable usage
  ansible.builtin.debug:
    msg: "Value is {{ my_var | default('fallback_value') }}"
# Skip task if variable is undefined
- name: Only run if variable exists
  ansible.builtin.debug:
    msg: "{{ optional_var }}"
  when: optional_var is defined

Strategy 3: Use vars_prompt for interactive input

---
- name: Ask for input
  hosts: all
  vars_prompt:
    - name: target_package
      prompt: "Which package to install?"
      default: "curl"
  tasks:
    - name: Install the package
      ansible.builtin.package:
        name: "{{ target_package }}"
        state: present
      become: true

Strategy 4: Role defaults

In roles, define default values in defaults/main.yml:

# roles/webserver/defaults/main.yml
http_port: 80
server_name: localhost
document_root: /var/www/html

These can be overridden by any other variable source but prevent "undefined" errors.

Strategy 5: Register variables from task output

- name: Get disk usage
  ansible.builtin.command: df -h /
  register: disk_result

- name: Show disk usage ansible.builtin.debug: msg: "{{ disk_result.stdout }}"

⚠️ Warning: register variables only exist for hosts where the task ran. If a task is skipped (via when), the registered variable won't exist on that host.

See also: Ansible Vault Error: Fix 'Attempting to Decrypt but No Vault Secrets Found'

Variable Precedence (simplified)

From lowest to highest priority: Role defaults (defaults/main.yml) Inventory group_vars Inventory host_vars Playbook vars: Role vars (vars/main.yml) Task vars: Extra vars (-e / --extra-vars)

If a variable is "undefined", check if it should be coming from one of these sources.

Debugging Undefined Variables

# Check what variables are available for a host
ansible hostname -m debug -a "var=hostvars[inventory_hostname]" -i inventory

# Check a specific variable ansible hostname -m debug -a "var=my_variable" -e @vars.yml -i inventory

# Run with verbose output to see variable resolution ansible-playbook playbook.yml -vvv

FAQ

How do I make a variable optional?

Use the default() Jinja2 filter:

msg: "{{ optional_var | default(omit) }}"  # Omits the parameter entirely
msg: "{{ optional_var | default('') }}"     # Uses empty string
msg: "{{ optional_var | default([]) }}"     # Uses empty list

How do I fail gracefully if a required variable is missing?

- name: Validate required variables
  ansible.builtin.assert:
    that:
      - database_host is defined
      - database_host | length > 0
    fail_msg: "database_host must be defined!"

Why does my variable work in one play but not another?

Variables set with set_fact or register are host-scoped — they persist across plays for the same host. But vars: defined at play level only exist within that play.

The Error

fatal: [host]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'my_var' is undefined"}

Quick Fixes

Use default Filter

# Provide fallback value
- debug: msg="{{ my_var | default('not set') }}"

# Default to empty list - debug: msg="{{ my_list | default([]) }}"

# Default to empty dict - debug: msg="{{ my_dict | default({}) }}"

# Chain defaults - debug: msg="{{ primary_var | default(secondary_var) | default('fallback') }}"

Check if Defined

- debug: msg="{{ my_var }}"
  when: my_var is defined

# Skip entire block - block: - template: src=app.conf.j2 dest=/etc/app.conf - service: name=myapp state=restarted when: app_config is defined

Assert Required Variables

- assert:
    that:
      - db_host is defined
      - db_host | length > 0
      - db_password is defined
    fail_msg: "Required database variables not set!"

Common Causes

Variable Not in Scope

# Variables set in one play don't carry to another
- hosts: webservers
  tasks:
    - set_fact: app_version=2.0

- hosts: dbservers tasks: - debug: msg="{{ app_version }}" # UNDEFINED! # Fix: use hostvars - debug: msg="{{ hostvars[groups['webservers'][0]].app_version }}"

Role Variables Not Available

# Role defaults only available within the role
# roles/myapp/defaults/main.yml
# app_port: 8080

# In playbook — can't access directly # Fix: Pass as role variable - hosts: all roles: - role: myapp vars: app_port: 9090

Registered Variable Conditional

# Variable only exists if task ran
- command: check-something
  register: result
  when: run_check | default(true)

# This fails if task was skipped! - debug: msg="{{ result.stdout }}"

# Fix: Check if defined - debug: msg="{{ result.stdout }}" when: result is defined and result is not skipped

Loop Variable Outside Loop

# WRONG - item only exists inside loop
- debug: msg="{{ item }}"
  loop: [a, b, c]
- debug: msg="{{ item }}"  # UNDEFINED!

Variable Precedence (Highest to Lowest)

Extra vars (-e) Task vars Block vars Role vars / include_vars Play vars Host facts / set_fact Inventory host_vars Inventory group_vars Role defaults

Debugging

# Verbose shows variable resolution
ansible-playbook site.yml -vvv

# Print all variables for a host ansible web1 -m debug -a "var=hostvars[inventory_hostname]"

# In playbook
- debug: var=vars  # All variables in scope
- debug: var=hostvars[inventory_hostname]

FAQ

Why is my group_vars variable undefined?

Check: file is in correct path (group_vars/.yml), host belongs to that group, and YAML syntax is valid.

How do I make a variable truly required?

- fail: msg="db_host must be set"
  when: db_host is not defined or db_host == ""

Can I set a global default for undefined variables?

# ansible.cfg — NOT recommended (hides bugs)
[defaults]
# error_on_undefined_vars = false  # Don't do this!

The Error

fatal: [web1]: FAILED! => {"msg": "'my_variable' is undefined"}

Quick Fixes

# Use default filter
msg: "{{ my_var | default('fallback') }}"

# Check if defined when: my_var is defined

# Require it (clear error message) msg: "{{ my_var | mandatory }}"

Common Causes

1. Variable Never Set

# FIX: Define in vars, group_vars, or defaults
- hosts: all
  vars:
    my_var: "value"

2. Typo in Variable Name

vars:
  database_host: db.example.com

# WRONG msg: "{{ databse_host }}" # Typo!

# CORRECT msg: "{{ database_host }}"

3. Scope Issue (set_fact)

# set_fact only sets for current host
- set_fact: my_var="hello"
  when: inventory_hostname == "web1"

# web2 doesn't have my_var! # FIX: use default - debug: msg="{{ my_var | default('not set') }}"

4. Facts Not Gathered

# gather_facts: false means no ansible_* facts
- hosts: all
  gather_facts: true  # Enable this

5. register from Skipped Task

- command: echo "hello"
  register: result
  when: false  # Task skipped!

# result is defined but has .skipped = true - debug: msg="{{ result.stdout | default('skipped') }}"

Safe Variable Patterns

# Nested access with default
"{{ config.database.host | default('localhost') }}"

# Check nested key exists when: config is defined and config.database is defined

# Default for entire dict "{{ (config | default({})).database | default({}).host | default('localhost') }}"

# Simpler with ternary "{{ config.database.host if config.database is defined else 'localhost' }}"

Debug Variables

# What type is it?
- debug: msg="{{ my_var | type_debug }}"

# Is it defined? - debug: msg="{{ my_var is defined }}"

# Print all variables - debug: var=hostvars[inventory_hostname]

Role Defaults

# roles/myrole/defaults/main.yml
# Always define defaults — prevents undefined errors
app_port: 8080
app_debug: false
app_log_level: info

FAQ

default('') vs default(omit)?

default('') gives empty string. default(omit) removes the parameter entirely (as if not specified).

How to make a variable required?

msg: "{{ required_var | mandatory }}"
# Gives clear error: "Mandatory variable 'required_var' not defined"

Undefined in Jinja2 template?

Same fixes — use {{ var | default('') }} or {% if var is defined %} blocks in templates.

Related Articles

Ansible role best practices

Category: installation

Watch the video: Ansible Fix Undefined Variable Error: Complete Troubleshooting Guide — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home