Ansible ignore_errors: Handle Task Failures (Complete Guide)
By Luca Berton · Published 2026-04-03 · Category: installation
Complete guide to Ansible ignore_errors. Handle task failures gracefully, use failed_when, rescue blocks, and control error behavior in playbooks.
By default, Ansible stops playbook execution when a task fails. The ignore_errors directive and related error handling features let you control this behavior.
ignore_errors: true
Continue playbook execution even if a task fails:
- name: Check if service exists (may fail)
ansible.builtin.command: systemctl status myapp
register: service_check
ignore_errors: true
- name: Install service if not present
ansible.builtin.apt:
name: myapp
state: present
when: service_check.rc != 0
Important: ignore_errors still marks the task as "failed" in the output — it just doesn't stop execution.
See also: Ansible ignore_errors: Error Handling Best Practices (Complete Guide)
ignore_unreachable: true
Specifically handle unreachable hosts (different from task failures):
- name: Check connectivity
ansible.builtin.ping:
ignore_unreachable: true
register: ping_result
- name: Skip unreachable hosts
ansible.builtin.debug:
msg: "Host is reachable"
when: not ping_result.unreachable | default(false)
failed_when: Custom Failure Conditions
Define your own failure criteria:
- name: Run database migration
ansible.builtin.command: /opt/app/migrate.sh
register: migration
failed_when:
- migration.rc != 0
- "'already up to date' not in migration.stdout"
- name: Check disk space
ansible.builtin.command: df -h /
register: disk_space
failed_when: "'100%' in disk_space.stdout"
Never fail (always succeed)
- name: Best-effort cleanup
ansible.builtin.command: rm -f /tmp/lockfile
failed_when: false
See also: Ansible ignore_errors: Skip Task Failures & Continue Playbook (Guide)
changed_when: Control Changed Status
Prevent false "changed" status:
- name: Check application version
ansible.builtin.command: /opt/app/version.sh
register: app_version
changed_when: false
failed_when: app_version.rc != 0
block/rescue/always: Try-Catch Pattern
- name: Deploy with rollback
block:
- name: Deploy new version
ansible.builtin.command: /opt/deploy.sh --version={{ new_version }}
- name: Run health check
ansible.builtin.uri:
url: http://localhost:8080/health
status_code: 200
rescue:
- name: Rollback on failure
ansible.builtin.command: /opt/deploy.sh --version={{ old_version }}
- name: Notify team
ansible.builtin.mail:
subject: "Deployment failed on {{ inventory_hostname }}"
to: ops@example.com
always:
- name: Clean up temp files
ansible.builtin.file:
path: /tmp/deploy-artifacts
state: absent
See also: Effective Techniques to Clear Host Errors in Ansible Playbooks
any_errors_fatal: Stop Everything
Stop the entire playbook across all hosts when any host fails:
- name: Critical pre-flight checks
hosts: all
any_errors_fatal: true
tasks:
- name: Verify disk space
ansible.builtin.assert:
that: ansible_mounts | selectattr('mount', 'equalto', '/') | map(attribute='size_available') | first > 1073741824
fail_msg: "Less than 1GB free disk space"
max_fail_percentage
Allow a percentage of hosts to fail before stopping:
- name: Rolling update
hosts: webservers
max_fail_percentage: 30
tasks:
- name: Update application
ansible.builtin.command: /opt/update.sh
Practical Examples
Check-and-act pattern
- name: Check if config exists
ansible.builtin.stat:
path: /etc/myapp/config.yml
register: config_file
- name: Generate default config if missing
ansible.builtin.template:
src: default-config.yml.j2
dest: /etc/myapp/config.yml
when: not config_file.stat.exists
Graceful service management
- name: Stop old service (may not exist)
ansible.builtin.systemd:
name: myapp-old
state: stopped
ignore_errors: true
register: stop_result
- name: Remove old service file
ansible.builtin.file:
path: /etc/systemd/system/myapp-old.service
state: absent
when: stop_result is not failed
FAQ
What's the difference between ignore_errors and failed_when: false?
ignore_errors: true marks the task as failed but continues. failed_when: false means the task is NEVER marked as failed. Use failed_when: false for truly inconsequential commands.
Does ignore_errors work with handlers?
Yes, but a failed task won't trigger handlers even with ignore_errors. Use changed_when to control handler triggering.
Can I ignore errors for an entire block?
Yes: put ignore_errors: true on the block directive.
Basic ignore_errors
- name: Try to stop old service
ansible.builtin.service:
name: legacy-app
state: stopped
ignore_errors: true
Check Error and Act
- name: Check if service exists
ansible.builtin.command: systemctl status myapp
register: service_check
ignore_errors: true
changed_when: false
- name: Install if missing
ansible.builtin.package:
name: myapp
state: present
when: service_check.rc != 0
become: true
ignore_unreachable
# Continue even if host is down
- name: Check if host is alive
ansible.builtin.ping:
ignore_unreachable: true
register: ping_result
- name: Skip unreachable hosts
debug:
msg: "Host {{ inventory_hostname }} is reachable"
when: ping_result is not unreachable
failed_when (Custom Failure Conditions)
# Don't fail on specific return codes
- name: Check if user exists
ansible.builtin.command: id username
register: user_check
failed_when: user_check.rc not in [0, 1]
changed_when: false
# Fail on specific output
- name: Run health check
ansible.builtin.uri:
url: http://localhost:8080/health
register: health
failed_when: "'unhealthy' in health.content"
block/rescue/always (Try-Catch)
- block:
- name: Deploy new version
ansible.builtin.git:
repo: https://github.com/myorg/app.git
dest: /opt/app
version: "{{ new_version }}"
- name: Run migrations
ansible.builtin.command: ./migrate.sh
args:
chdir: /opt/app
rescue:
- name: Rollback on failure
ansible.builtin.git:
repo: https://github.com/myorg/app.git
dest: /opt/app
version: "{{ old_version }}"
- name: Notify team
ansible.builtin.uri:
url: https://hooks.slack.com/xxx
method: POST
body: '{"text": "Deployment failed, rolled back"}'
always:
- name: Restart service
ansible.builtin.service:
name: myapp
state: restarted
become: true
Error Handling Comparison
| Method | Use Case |
|--------|----------|
| ignore_errors: true | Continue regardless of failure |
| failed_when | Custom failure conditions |
| block/rescue | Try-catch with rollback |
| ignore_unreachable | Handle offline hosts |
| any_errors_fatal | Stop ALL hosts on any failure |
| max_fail_percentage | Allow some hosts to fail |
any_errors_fatal
- hosts: webservers
any_errors_fatal: true # Stop entire play if ANY host fails
serial: 1
tasks:
- name: Critical deployment
command: ./deploy.sh
FAQ
Does ignore_errors skip handlers?
No — if the task that notified a handler reported changed (even with an error), the handler still runs.
How do I fail the play later based on ignored errors?
- command: /opt/check.sh
register: result
ignore_errors: true
# ... more tasks ...
- fail:
msg: "Earlier check failed: {{ result.stderr }}"
when: result.rc != 0
What's the difference between ignore_errors and failed_when: false?
Both prevent failure, but failed_when: false means the task never fails (always shows ok/changed). ignore_errors: true still marks it as failed in output but continues.
Basic ignore_errors
- ansible.builtin.command: /opt/check-service.sh
register: result
ignore_errors: true
- debug:
msg: "Check failed but continuing: {{ result.stderr }}"
when: result.failed
ignore_errors vs failed_when
# ignore_errors — task "fails" but play continues
- command: /opt/optional-check.sh
ignore_errors: true
# failed_when — redefine what "failure" means
- command: /opt/check.sh
register: result
failed_when: result.rc not in [0, 1]
# rc=0 or rc=1 = success; anything else = failure
Handle Errors with block/rescue
- block:
- name: Try to deploy
command: /opt/deploy.sh
- name: Verify deployment
uri: { url: "http://localhost/health", status_code: 200 }
rescue:
- name: Rollback on failure
command: /opt/rollback.sh
- name: Notify team
uri:
url: https://hooks.slack.com/...
method: POST
body: '{"text": "Deploy failed, rolled back"}'
always:
- name: Clean up temp files
file: { path: /tmp/deploy-artifacts, state: absent }
Conditional Error Handling
- command: /opt/check.sh
register: check
ignore_errors: true
- name: Handle failure
debug:
msg: "Check failed with: {{ check.stderr }}"
when: check.failed
- name: Continue on success
debug:
msg: "Check passed: {{ check.stdout }}"
when: not check.failed
ignore_unreachable
# Continue even if host is down
- ping:
ignore_unreachable: true
register: ping_result
- debug:
msg: "Host {{ inventory_hostname }} is unreachable"
when: ping_result.unreachable | default(false)
any_errors_fatal
# Stop ALL hosts if ANY host fails
- hosts: webservers
any_errors_fatal: true
tasks:
- name: Critical check
command: /opt/pre-deploy-check.sh
# If this fails on ANY host, entire play stops
max_fail_percentage
# Allow up to 20% of hosts to fail
- hosts: webservers
max_fail_percentage: 20
serial: 10
tasks:
- name: Rolling deploy
command: /opt/deploy.sh
changed_when with Error Handling
- command: /opt/idempotent-script.sh
register: result
changed_when: "'CHANGED' in result.stdout"
failed_when: result.rc > 1 # Only fail on rc > 1
Common Patterns
# Check if service exists before managing it
- command: systemctl cat myapp
register: service_check
ignore_errors: true
changed_when: false
- service: { name: myapp, state: restarted }
when: service_check.rc == 0
# Optional package removal
- apt: { name: old-package, state: absent }
ignore_errors: true # OK if package not found
become: true
# Graceful degradation
- uri:
url: http://api.example.com/data
timeout: 5
register: api_call
ignore_errors: true
- set_fact:
api_data: "{{ api_call.json if not api_call.failed else {} }}"
FAQ
Does ignore_errors affect handlers?
Yes — if a task with ignore_errors: true notifies a handler and fails, the handler is still triggered (because the play continues).
ignore_errors vs block/rescue?
ignore_errors silently continues. block/rescue lets you execute recovery logic. Use rescue for production workflows.
Does ignore_errors count as a failure?
The task shows as "failed" (red) in output but the play continues. ansible_failed_result is set. Use failed_when: false to not mark it as failed at all.
Basic ignore_errors
- ansible.builtin.command: /opt/check-status.sh
ignore_errors: true
register: status_check
Check Result After Ignoring
- command: /opt/check-service.sh
register: result
ignore_errors: true
- debug:
msg: "Service is down!"
when: result.rc != 0
- debug:
msg: "Service is running"
when: result.rc == 0
failed_when (Better Control)
# Only fail on specific conditions
- command: /opt/deploy.sh
register: deploy
failed_when:
- deploy.rc != 0
- "'already running' not in deploy.stderr"
ignore_unreachable
# Continue even if host is unreachable
- ping:
ignore_unreachable: true
register: ping_result
- debug:
msg: "Host {{ inventory_hostname }} is down"
when: ping_result.unreachable is defined
Block/Rescue (Try/Catch)
- block:
- command: /opt/deploy.sh
- service:
name: myapp
state: started
rescue:
- debug:
msg: "Deploy failed, rolling back"
- command: /opt/rollback.sh
always:
- debug:
msg: "Cleanup complete"
any_errors_fatal
# Stop ALL hosts if ANY host fails
- hosts: webservers
any_errors_fatal: true
tasks:
- command: /opt/critical-check.sh
max_fail_percentage
# Fail play if >25% hosts fail
- hosts: webservers
max_fail_percentage: 25
tasks:
- service:
name: myapp
state: started
changed_when with ignore_errors
- command: /opt/check.sh
register: check
ignore_errors: true
changed_when: false # Never report changed
FAQ
ignore_errors vs failed_when?
ignore_errors continues regardless of failure. failed_when lets you define what constitutes a failure. Prefer failed_when for precise control.
Does ignore_errors affect handlers?
No — handlers still won't run for failed tasks even with ignore_errors. The task is still marked as failed.
How to fail the play later based on ignored errors?
- fail:
msg: "Critical check failed earlier"
when: earlier_result.rc != 0
Related Articles
• template lookups in Ansible • handler ordering in Ansible • Ansible when Conditional Guide • Ansible Inventory Guide • Ansible Ignore Errors GuideCategory: installation