SynfraCore
Synfracore
Start Learning
Navigation

Academies

Platform

RoadmapsLabsCertificationsInterviewPYQsAI AssistantCareer
Start Learning Free🗺️ Learning Roadmaps

AnsibleTroubleshooting

Debug common issues with root cause analysis

✍️
Written by senior engineers. Reviewed for technical accuracy.· Updated 2025 · SynfraCore Ansible Team
Expert Content

Ansible Troubleshooting Guide

Issue 1: SSH connection failures

Symptom: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh"}

Root Cause: SSH key not accepted, host not in known_hosts, wrong user, or firewall blocking port 22.

Debug steps:

bash
# Test SSH manually
ssh -i ~/.ssh/id_rsa user@target-host -v  # verbose SSH

# Test Ansible connection
ansible myhost -m ping -vvv
ansible myhost -m ping --ask-pass   # use password auth

# Check inventory
ansible-inventory -i inventory --list

Fix patterns:

ini
# inventory/hosts.ini
[webservers]
192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/key.pem
192.168.1.11 ansible_user=ec2-user ansible_port=2222  # non-standard port
bash
# Add to known_hosts automatically
ansible.cfg: [defaults] host_key_checking = False  # for testing only

Issue 2: Task says 'changed' every run (not idempotent)

Symptom: Same task shows changed=1 on every playbook run even if nothing actually changed.

Root Cause: Using command/shell modules which are never idempotent, or module not checking state properly.

Debug steps:

bash
ansible-playbook playbook.yml --check  # dry-run
ansible-playbook playbook.yml --diff   # show what changed

Fix patterns:

yaml
# WRONG: shell is not idempotent
- name: Create directory
  shell: mkdir -p /opt/myapp

# RIGHT: file module is idempotent
- name: Create directory
  file:
    path: /opt/myapp
    state: directory
    mode: '0755'

# For command module: use creates/removes to make idempotent
- name: Extract archive
  command: tar xzf /tmp/app.tar.gz -C /opt/
  args:
    creates: /opt/app/  # only runs if this path doesn't exist

Issue 3: Variable not defined error

Symptom: AnsibleUndefinedVariable: 'variable_name' is undefined

Root Cause: Variable not set in inventory, group_vars, host_vars, or passed via -e.

Debug steps:

bash
# Check what variables are available
ansible hostname -m debug -a "var=hostvars[inventory_hostname]"

# Show all variables for a host
ansible-inventory -i inventory --host hostname --vars

# Run with verbose
ansible-playbook playbook.yml -vvv

Fix patterns:

yaml
# Set defaults for optional variables
- name: Use variable with default
  debug:
    msg: "{{ my_var | default('default_value') }}"

# Conditional on variable existence
- name: Only run if variable set
  command: echo {{ my_var }}
  when: my_var is defined

Issue 4: Vault decryption fails

Symptom: ERROR! Decryption failed (no vault secrets were found that could decrypt)

Root Cause: Wrong vault password, missing vault password file, or vault ID mismatch.

Debug steps:

bash
ansible-vault view secrets.yml --ask-vault-pass
ansible-vault decrypt secrets.yml --output=/tmp/check.yml

Fix patterns:

bash
# Method 1: password file
echo "my_vault_password" > .vault_pass
chmod 600 .vault_pass
ansible-playbook playbook.yml --vault-password-file .vault_pass

# Method 2: environment variable
export ANSIBLE_VAULT_PASSWORD_FILE=.vault_pass

# Method 3: vault ID
ansible-vault encrypt secrets.yml --vault-id prod@.vault_pass
ansible-playbook playbook.yml --vault-id prod@.vault_pass

Issue 5: Task runs but changes are not applied

Symptom: Playbook completes successfully but system state didn't change as expected.

Root Cause: become: yes not set, check mode enabled, handler not notified, or wrong target.

Debug steps:

bash
# Verify become
ansible hostname -m command -a "whoami" --become  # should return root

# Check if in check mode
ansible-playbook playbook.yml --check   # dry run only

# Verify handler triggers
ansible-playbook playbook.yml -v  # shows handler notifications

Fix patterns:

yaml
# Ensure become for privileged operations
- name: Install nginx
  apt:
    name: nginx
    state: present
  become: yes          # sudo

# Force handler execution immediately
- name: Update nginx config
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: restart nginx

- name: Force handlers
  meta: flush_handlers  # runs handlers immediately

Prevention Tips

Always test with --check --diff before running in production
Use --limit hostname to target single host during testing
Enable log_path = /var/log/ansible.log in ansible.cfg for auditing
Use serial: 1 for rolling updates to catch issues before full deployment
Add any_errors_fatal: true for critical playbooks that must not partially succeed
Share:
Join our Community
Daily tips, job alerts, interview help — join engineers learning together
Up Next
🏆
AnsibleCertification
Exam guides, practice questions, and prep strategies
Also Worth Exploring
← Back to all Ansible modules
Interview Q&ACertification