How to Make Ansible Fail Explicitly When Required Variables Are Missing in YAML


2 views

Many Ansible users encounter this frustrating behavior: when referencing undefined variables in playbooks, Ansible silently replaces them with empty strings instead of failing. This default behavior can lead to subtle bugs that only surface during runtime, especially when dealing with mandatory configuration parameters.

In production environments, undefined variables typically indicate configuration errors that should fail fast rather than continue with potentially dangerous defaults. Consider this common scenario:


# playbook.yml
- name: Configure web server
  hosts: webservers
  vars_files:
    - config.yml
  tasks:
    - name: Ensure Apache is installed
      apt:
        name: apache2
        state: present
      when: install_apache

If install_apache is undefined, the task silently skips rather than alerting you to the missing configuration.

Ansible provides several mechanisms to make variable validation more strict:


# ansible.cfg
[defaults]
error_on_undefined_vars = True

# Alternative per-playbook approach
- name: Strict variable checking
  hosts: all
  vars:
    required_vars:
      - db_host
      - db_port
      - api_key
  tasks:
    - name: Validate required variables
      assert:
        that: lookup('vars', item) is defined
        fail_msg: "Required variable '{{ item }}' is missing"
      with_items: "{{ required_vars }}"

For more sophisticated validation, combine these approaches:


# roles/common/tasks/validate_vars.yml
- name: Check for undefined mandatory variables
  fail:
    msg: "Mandatory variable '{{ item.key }}' is not defined"
  when: item.value is undefined
  with_dict: "{{ mandatory_vars }}"

# In your playbook
vars:
  mandatory_vars:
    db_connection: "{{ db_host }}:{{ db_port }}"
    secret_key: "{{ vault_secret_key }}"

Remember that Ansible's variable precedence affects these checks. A variable might be defined at a higher precedence level than where you're checking. The default filter can help distinguish between intentionally empty values and truly undefined ones:


- name: Validate with default filter
  assert:
    that: "{{ some_var | default('THIS_IS_UNDEFINED') != 'THIS_IS_UNDEFINED' }}"
    fail_msg: "some_var must be defined (empty is allowed)"

When working with Ansible playbooks, you might have noticed that referencing undefined variables doesn't cause the playbook to fail by default. Instead, Ansible silently substitutes them with empty strings. This behavior can lead to:

  • Hidden configuration issues
  • Unexpected application behavior
  • Difficult-to-debug problems

To make Ansible fail when encountering undefined variables, you have several options:

1. Global Configuration

Add this to your ansible.cfg:

[defaults]
error_on_undefined_vars = True

2. Playbook-Level Option

Set it at the playbook level:

- hosts: all
  vars:
    required_var: "{{ undefined_var }}"
  tasks:
    - debug:
        msg: "This will fail if undefined_var is not set"
  vars_prompt:
    - name: undefined_var
      prompt: "Enter a value for undefined_var"
      private: no

3. Using the mandatory Filter

For more granular control:

- hosts: all
  tasks:
    - debug:
        msg: "{{ undefined_var | mandatory }}"

Consider this problematic playbook:

- name: Configure web server
  hosts: webservers
  vars:
    http_port: "{{ web_port }}"
  tasks:
    - name: Ensure Apache is running
      service:
        name: httpd
        state: started
        enabled: yes

If web_port is undefined, the playbook will run with an empty string. To fix this:

- name: Configure web server
  hosts: webservers
  vars:
    http_port: "{{ web_port | mandatory('web_port must be defined') }}"
  tasks:
    - name: Ensure Apache is running
      service:
        name: httpd
        state: started
        enabled: yes

For complex scenarios, you can combine these approaches:

- name: Validate all required variables
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: Check required variables
      assert:
        that:
          - "required_var1 is defined"
          - "required_var2 is defined"
        fail_msg: "Missing required variables"
  • Always validate variables early in your playbook
  • Use descriptive error messages with mandatory
  • Consider using default() filter for optional variables
  • Document all required variables in playbook comments