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 & assert • Ansible Undefined Variable Error: Fixes • Ansible 12 Upgrade Guide • Ansible Check Mode / Dry Run GuideCategory: troubleshooting