Subtopic•Handling Errors

Error Handling Overview

In the previous module, we finished our study of Ansible Vault, which secures credentials and secrets across different environments. Now, we will look at execution flow control: what happens when tasks fail, and how you manage errors in your playbooks.

By default, Ansible expects tasks to succeed. If a task returns a failed status on a host, Ansible's default behavior is to immediately halt execution for that host, skip all remaining tasks in the playbook for it, and mark the host as failed in the final play recap.

Understanding this failure model and knowing how to control it is essential for writing resilient playbooks that can recover from expected failures without crashing your entire deployment run.

1. The Default Failure Model

When a task fails on a remote host, Ansible executes a specific sequence:

Task Execution Failure
       │
       ▼
1. Mark host as "Failed" in active play scope
2. Remove host from active execution queue for the current play
3. Skip all remaining tasks in the current play for that host
4. Print failure details to stdout / console logs
5. Update play recap status: failed=1

Let's look at a basic example where a task fails due to a missing package:

---
- name: Deploy application dependencies
  hosts: webservers
  become: yes

  tasks:
    - name: Run status validation script
      ansible.builtin.command: /opt/app/bin/validate_status.sh
      # If this script exits with a non-zero exit code (e.g. 1), the task fails

    - name: Copy configuration file
      ansible.builtin.copy:
        src: app.conf
        dest: /etc/myapp/app.conf

If the validation script fails on web-prod-01, Ansible stops executing. The configuration file copy task is skipped for web-prod-01. However, if the script succeeds on web-prod-02, it continues running tasks for that host normally.


2. Managing Multiple Host Failures

If you are running a playbook against hundreds of hosts, a single host failing on a non-critical task should not necessarily abort your deployment for all other hosts.

Ansible runs plays in parallel across hosts using forks. Each host maintains its own execution state:

  • A failure on host-01 does not stop execution on host-02.
  • Hosts execute tasks in lockstep: all hosts execute Task 1. Once complete, those that succeeded execute Task 2.
  • If a host fails at any step, it is "evicted" from the current play, and the remaining hosts continue to the next task.

3. Controlling Failure thresholds: max_fail_percentage

If you are running rolling updates across a large server cluster, you might want to stop the entire play if a significant percentage of hosts fail.

To configure this, use the max_fail_percentage play-level parameter. This tells Ansible to abort the play for all hosts if the number of failed hosts exceeds your threshold:

---
- name: Rolling application deployment
  hosts: webservers
  become: yes
  # Abort the entire play if more than 10% of hosts fail
  max_fail_percentage: 10
  serial: 10           # Run in batches of 10 hosts

  tasks:
    - name: Deploy application update
      ansible.builtin.command: /opt/app/bin/update.sh

In this setup, if you have 100 hosts and run in batches of 10 (serial: 10), and more than 10 hosts fail during execution, Ansible aborts the entire run immediately, preventing a broken configuration from rolling out to the rest of the cluster.


4. Error Handling Tools in Ansible

To override the default failure model, Ansible provides several task-level directives:

  • ignore_errors: Allows execution to continue even if a task fails.
  • failed_when: Defines custom criteria for what constitutes a task failure.
  • changed_when: Controls whether a task reports a change status.
  • any_errors_fatal: Forces the playbook to stop immediately for all hosts if any single host fails.

We will cover each of these options in detail in the following sections.


Summary

The default Ansible failure model aborts execution for any host that encounters a task failure. By using batch controls like serial and percentage limits like max_fail_percentage, you can control how errors affect cluster deployments. In the next section, we will cover how to use ignore_errors to let specific non-critical tasks fail without halting execution.

←Previous ModuleAnsible Vault