AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible debug vs assert: When to Use Each Module

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Complete comparison of Ansible debug and assert modules. Learn when to use debug for inspecting variables and assert for validating conditions, with practical.

debug and assert are both used during development and troubleshooting, but they solve fundamentally different problems. debug shows you data. assert validates conditions and fails the play if they're not met.

Quick Comparison

| Feature | debug | assert | |---------|-------|--------| | Purpose | Display information | Validate conditions | | Fails on false | Never | Yes | | Stops playbook | Never | Yes (unless ignore_errors) | | Output | Variable values, messages | Success/failure + custom message | | Use case | Inspection, troubleshooting | Validation, pre-flight checks | | Production use | Rarely (remove after debugging) | Always (keep as guardrails) |

See also: Ansible debug Module: Print Variables & Messages (Complete Guide)

debug: Inspect and Display

Show a Variable

- name: Show server config
  ansible.builtin.debug:
    var: ansible_default_ipv4
# Output:
# ok: [web01] => {
#     "ansible_default_ipv4": {
#         "address": "10.0.1.10",
#         "interface": "eth0",
#         ...
#     }
# }

Show a Message

- name: Display deployment info
  ansible.builtin.debug:
    msg: "Deploying {{ app_name }} v{{ version }} to {{ inventory_hostname }}"

Control Verbosity

# Only shown with -v
- ansible.builtin.debug:
    msg: "Detailed config: {{ all_config }}"
    verbosity: 1

# Only shown with -vv - ansible.builtin.debug: msg: "Full variable dump" verbosity: 2 var: hostvars[inventory_hostname]

Common debug Patterns

# Debug registered output
- ansible.builtin.command: df -h /
  register: disk
- ansible.builtin.debug:
    var: disk.stdout_lines

# Debug loop items - ansible.builtin.debug: msg: "Processing {{ item.name }} ({{ item.state }})" loop: "{{ services }}"

# Debug complex expressions - ansible.builtin.debug: msg: "{{ users | selectattr('role', 'equalto', 'admin') | map(attribute='name') | list }}"

assert: Validate and Guard

Basic Assertion

- name: Validate required variables
  ansible.builtin.assert:
    that:
      - version is defined
      - version | length > 0
      - environment in ['staging', 'production']
    fail_msg: "Missing or invalid deploy parameters. Need: -e version=X.Y.Z -e environment=staging|production"
    success_msg: "Parameters validated: v{{ version }} → {{ environment }}"

Pre-Flight Checks

- name: Pre-flight validation
  ansible.builtin.assert:
    that:
      - ansible_distribution == "Ubuntu"
      - ansible_distribution_major_version | int >= 22
      - ansible_memtotal_mb >= 2048
      - ansible_processor_vcpus >= 2
    fail_msg: >-
      Host {{ inventory_hostname }} doesn't meet requirements:
      Need Ubuntu 22+, 2GB RAM, 2 CPUs.
      Got {{ ansible_distribution }} {{ ansible_distribution_version }},
      {{ ansible_memtotal_mb }}MB RAM, {{ ansible_processor_vcpus }} CPUs.

Validate Task Output

- name: Check service health
  ansible.builtin.uri:
    url: "http://localhost:8080/health"
  register: health

- name: Verify service is healthy ansible.builtin.assert: that: - health.status == 200 - health.json.status == "UP" - health.json.database == "connected" fail_msg: "Health check failed: {{ health.json | default('no response') }}"

Quiet Mode

# Don't show individual assertion results (cleaner output)
- name: Validate config
  ansible.builtin.assert:
    that:
      - db_host is defined
      - db_port | int > 0
      - db_name | length > 0
    quiet: true    # Only shows if assertion fails

See also: Ansible for Windows: Complete Guide to Windows Automation (2026)

When to Use Each

Use debug When

# Troubleshooting — "what does this variable contain?"
- ansible.builtin.debug:
    var: result

# Development — "is my filter working?" - ansible.builtin.debug: msg: "{{ data | json_query('servers[?state==`running`].name') }}"

# Logging — "what happened during this run?" - ansible.builtin.debug: msg: "Deployed {{ version }} at {{ ansible_date_time.iso8601 }}"

Use assert When

# Validation — "fail fast if requirements aren't met"
- ansible.builtin.assert:
    that: ansible_os_family == "Debian"
    fail_msg: "This playbook only supports Debian-based systems"

# Guardrails — "prevent dangerous operations" - ansible.builtin.assert: that: environment != "production" or deploy_approved | default(false) | bool fail_msg: "Production deploys require -e deploy_approved=true"

# Post-conditions — "verify the task did what we expected" - ansible.builtin.assert: that: migration_result.stdout is search("Successfully migrated")

Combined Pattern: Debug + Assert

# Show the data, then validate it
- name: Get service status
  ansible.builtin.uri:
    url: "http://{{ inventory_hostname }}:8080/status"
  register: status

- name: Show status (for troubleshooting) ansible.builtin.debug: var: status.json verbosity: 1 # Only in verbose mode

- name: Validate service is ready ansible.builtin.assert: that: - status.json.ready | bool - status.json.connections | int < status.json.max_connections | int fail_msg: "Service not ready on {{ inventory_hostname }}"

See also: Ansible assert Module: Validate Conditions and Fail Early (Complete Guide)

ansible-core 2.19 Note

In ansible-core 2.19, assert conditions must return actual booleans:

# ❌ BREAKS in 2.19 — truthy string, not boolean
- ansible.builtin.assert:
    that: inventory_hostname

# ✅ WORKS — explicit boolean - ansible.builtin.assert: that: inventory_hostname | length > 0

See Ansible 12 Upgrade Guide for full details.

FAQ

Should I leave debug tasks in production playbooks?

Generally no. Remove debug tasks or set verbosity: 1 so they only appear with -v. Exception: important deploy summaries that serve as log entries.

Can assert be used as a dry-run validation?

Yes — assert is perfect for pre-flight checks. Run validation tasks at the start of your playbook to fail fast before making any changes. Combine with --check mode for comprehensive dry runs.

What happens when assert fails?

The task fails, and by default the playbook stops for that host. Use ignore_errors: true to continue (not recommended for critical validations), or any_errors_fatal: true to stop the entire play across all hosts.

Can I use assert in a loop?

Yes, but each assertion failure stops the loop. Use loop + assert for validating a list of conditions, or build a single that: list dynamically.

Conclusion

debug is your microscope — use it to inspect data during development and troubleshooting. assert is your guardrail — use it to validate conditions and fail fast when requirements aren't met. Keep debug temporary; keep assert permanent.

Related Articles

Ansible Conditionals: when & assertAnsible Undefined Variable Error: FixesAnsible 12 Upgrade GuideAnsible Check Mode / Dry Run Guide

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home