What's Actually Happening

Ansible playbook runs without loading host-specific variables from inventory. Variables defined in host_vars or inventory file are not available during playbook execution, causing tasks to fail or use wrong values.

The Error You'll See

Variable undefined:

```bash $ ansible-playbook site.yml -l server1

TASK [Configure app] *************** fatal: [server1]: FAILED! => { "msg": "The task includes an undefined variable 'app_port'." } ```

Wrong variable value:

```bash $ ansible server1 -m debug -a "var=app_port"

server1 | SUCCESS => { "app_port": 8080 # Expected 9000 from inventory } ```

Inventory not loaded:

```bash $ ansible-inventory --list

{ "_meta": { "hostvars": {} # Empty, host variables not found } } ```

Why This Happens

  1. 1.Wrong inventory path - Ansible not finding inventory file
  2. 2.Invalid inventory format - YAML syntax errors
  3. 3.host_vars directory wrong - Not in correct location
  4. 4.Variable precedence override - Other sources overriding
  5. 5.Group vs host variables - Variables in wrong scope
  6. 6.Inventory file not parsed - Format not recognized

Step 1: Check Inventory Path

```bash # Check current inventory path ansible-config dump | grep inventory

# Default locations: # - ansible.cfg: inventory = /path/to/inventory # - Environment: ANSIBLE_INVENTORY # - CLI: -i /path/to/inventory

# Check ansible.cfg grep inventory ansible.cfg

# Common settings: [defaults] inventory = ./inventory # Or: inventory = ./hosts.ini,./inventory/

# Test inventory loading ansible-inventory --list -i ./inventory

# Verify hosts found ansible all -i ./inventory --list-hosts

# Check if using correct inventory ansible-playbook site.yml -i ./inventory -v ```

Step 2: Verify Inventory File Format

```bash # Check inventory file exists ls -la inventory/ ls -la hosts.ini

# Validate YAML inventory syntax python -c "import yaml; yaml.safe_load(open('inventory.yaml'))"

# Or use ansible-inventory ansible-inventory -i inventory.yaml --list

# Valid YAML inventory format: --- all: hosts: server1: app_port: 9000 app_user: deploy server2: app_port: 8080 app_user: admin children: web: hosts: server1: server2: vars: nginx_port: 80

# INI format (hosts.ini): [web] server1 app_port=9000 app_user=deploy server2 app_port=8080 app_user=admin

[web:vars] nginx_port=80

# Validate INI format ansible-inventory -i hosts.ini --list ```

Step 3: Check host_vars Directory

```bash # host_vars should be adjacent to inventory file # Structure: # inventory/ # hosts.ini # group_vars/ # web.yml # host_vars/ # server1.yml # server2.yml

ls -la inventory/host_vars/ ls -la inventory/host_vars/server1.yml

# Check file content cat inventory/host_vars/server1.yml

--- app_port: 9000 app_user: deploy

# Verify ansible sees host_vars ansible-inventory --list -i inventory/hosts.ini

# Should show: { "_meta": { "hostvars": { "server1": { "app_port": 9000 } } } }

# If host_vars not adjacent to inventory, specify: ansible-playbook site.yml -i inventory/hosts.ini --extra-vars "@host_vars/server1.yml" ```

Step 4: Test Variable Loading

```bash # Debug variable value ansible server1 -m debug -a "var=app_port" -i inventory/

# Debug all host variables ansible server1 -m debug -a "var=hostvars[inventory_hostname]" -i inventory/

# Check inventory hierarchy ansible-inventory --graph -i inventory/

# Use verbose mode to see variable sources ansible-playbook site.yml -i inventory/ -vvv | grep app_port

# Show variable precedence ansible server1 -m debug -a "var=ansible_vars_sources" -i inventory/ ```

Step 5: Check Variable Precedence

```bash # Ansible variable precedence (lowest to highest): # 1. command line values (lowest) # 2. role defaults # 3. inventory file or script group vars # 4. inventory group_vars/all # 5. playbook group_vars/all # 6. inventory group_vars/* # 7. playbook group_vars/* # 8. inventory file or script host vars # 9. inventory host_vars/* # 10. playbook host_vars/* # 11. host facts / cached set_facts # 12. play vars # 13. play vars_prompt # 14. play vars_files # 15. role vars # 16. block vars # 17. task vars # 18. include_vars # 19. set_facts / registered vars # 20. role (and include_role) params # 21. include_params # 22. extra vars (highest)

# Check if variable being overridden ansible server1 -m debug -a "var=app_port" -vvv

# Check playbook variables grep app_port playbook.yml

# Check role defaults grep -r app_port roles/*/defaults/

# Check extra vars ansible-playbook site.yml -e "app_port=8080" # This overrides inventory host_vars! ```

Step 6: Fix Inventory Directory Structure

```bash # Correct structure for inventory directory:

mkdir -p inventory/group_vars inventory/host_vars

# Create inventory file cat << 'EOF' > inventory/hosts.ini [web] server1 server2

[db] server3 EOF

# Create host_vars cat << 'EOF' > inventory/host_vars/server1.yml --- app_port: 9000 app_user: deploy EOF

cat << 'EOF' > inventory/host_vars/server2.yml --- app_port: 8080 app_user: admin EOF

# Create group_vars cat << 'EOF' > inventory/group_vars/web.yml --- nginx_port: 80 nginx_user: www-data EOF

# Verify structure tree inventory/ # inventory/ # ├── hosts.ini # ├── group_vars/ # │ └── web.yml # └── host_vars/ # │ ├── server1.yml # │ └── server2.yml

# Test loading ansible-inventory -i inventory/hosts.ini --list ```

Step 7: Use Dynamic Inventory Correctly

```bash # For dynamic inventory plugins

# Check plugin configuration ansible-config dump | grep inventory_plugins

# Example AWS inventory plugin: # inventory/aws_ec2.yml plugin: aws_ec2 regions: - us-east-1 hostvars: app_port: 9000

# Verify plugin loaded ansible-inventory -i inventory/aws_ec2.yml --list

# For custom inventory scripts: ansible-inventory -i inventory/my_script.py --list

# Check script is executable chmod +x inventory/my_script.py

# Test script output python inventory/my_script.py # Should output valid JSON

# Multiple inventory sources: ansible-playbook site.yml -i inventory/hosts.ini -i inventory/aws_ec2.yml ```

Step 8: Verify Host Name Matching

```bash # host_vars file name must match host name exactly

# Check host names in inventory ansible-inventory --list -i inventory/hosts.ini | jq '.all.hosts'

# Host names: # server1, server2

# host_vars files must be: # inventory/host_vars/server1.yml # inventory/host_vars/server2.yml

# NOT: # inventory/host_vars/server1.local.yml # Wrong if host is 'server1' # inventory/host_vars/192.168.1.1.yml # Wrong if host is 'server1'

# Check if host_vars file matches host ls inventory/host_vars/

# If host name includes domain, include in filename: # Host: server1.example.com # File: inventory/host_vars/server1.example.com.yml

# Or use aliases in INI inventory: [web] server1 ansible_host=192.168.1.1 # host_vars/server1.yml will load ```

Step 9: Force Variable Reload

```bash # Clear ansible cache rm -rf ~/.ansible/cache/ rm -rf .ansible/

# Reload facts ansible server1 -m setup -i inventory/

# Use --flush-cache ansible-playbook site.yml -i inventory/ --flush-cache

# Force re-read inventory ansible-inventory -i inventory/hosts.ini --list --refresh

# Check ansible inventory manager ansible-config dump | grep inventory_cache

# Disable caching in ansible.cfg: [defaults] fact_caching = memory inventory_cache = false ```

Step 10: Debug Variable Sources

```bash # Create playbook to debug variable precedence cat << 'EOF' > debug_vars.yml --- - hosts: all tasks: - name: Debug app_port value debug: var: app_port

  • name: Debug all host vars
  • debug:
  • var: hostvars[inventory_hostname]
  • name: Debug inventory hostname
  • debug:
  • var: inventory_hostname
  • name: Debug group names
  • debug:
  • var: group_names
  • name: Show variable source
  • shell: echo "app_port from host_vars"
  • when: app_port == 9000
  • EOF

ansible-playbook debug_vars.yml -i inventory/ -vv

# Use ansible-doc for inventory plugin help ansible-doc -t inventory aws_ec2 ansible-doc -t inventory yaml ```

Ansible Inventory Variables Checklist

CheckCommandExpected
Inventory pathansible-config dumpCorrect path
Host vars filels host_vars/Matches host name
Variable valuedebug var=Expected value
Inventory graph--graphShows host_vars
YAML syntaxpython yaml.loadNo errors
Precedencedebug -vvvNo override

Verify the Fix

```bash # After fixing inventory variable loading

# 1. Verify host_vars loaded ansible-inventory --list -i inventory/ | jq '.["_meta"]["hostvars"]["server1"]' // Should show host variables

# 2. Check variable value ansible server1 -m debug -a "var=app_port" -i inventory/ // Should show expected value (9000)

# 3. Run playbook successfully ansible-playbook site.yml -i inventory/ -l server1 // Tasks should use correct variable values

# 4. Verify no override ansible-playbook site.yml -vvv | grep app_port // Should show value from host_vars

# 5. Check inventory graph ansible-inventory --graph -i inventory/ // Shows host variables attached to hosts

# 6. Test with multiple hosts ansible all -m debug -a "var=app_port" -i inventory/ // Each host shows its own port ```

  • [Fix Ansible Variable Undefined](/articles/fix-ansible-variable-undefined)
  • [Fix Ansible Inventory Not Found](/articles/fix-ansible-inventory-not-found)
  • [Fix Ansible Group Variables Not Applied](/articles/fix-ansible-group-variables-not-applied)