Your playbook runs but tasks execute when they shouldn't, or don't execute when they should. Condition evaluation errors in Ansible's when clauses cause unpredictable behavior and silent failures.
Understanding the Error
Condition errors manifest differently:
fatal: [webserver01]: FAILED! => {"msg": "The conditional check 'item == true' failed. The error was: error while evaluating conditional (item == true): 'item' is undefined"}Or subtler - tasks running incorrectly:
- name: Should skip
debug:
msg: "This should not run"
when: False # Actually true due to string comparisonOr syntax errors:
ERROR! 'when' clause 'item = value' is invalid: must be Jinja2 expressionStep 1: Understand When Syntax
when accepts Jinja2 expressions:
```yaml # CORRECT - Jinja2 expression when: ansible_os_family == "Debian"
# WRONG - assignment syntax when: ansible_os_family = "Debian" ```
The result must evaluate to a boolean-like value:
- true, yes, 1 - runs task
- false, no, 0, empty string - skips task
Step 2: Fix String vs Boolean Comparison
A common pitfall - string comparison with boolean:
```yaml # WRONG - string "true" vs boolean True when: result == true # If result is string "true", this fails
# CORRECT - type-aware comparison when: result == True # Boolean True when: result == "true" # String "true" when: result | bool # Convert to boolean ```
Check what type your variable is:
- name: Debug variable type
debug:
msg: "Type: {{ result | type_debug }}"Output: str or bool or int.
Step 3: Handle Undefined Variables
When clauses fail if variables are undefined:
```yaml # WRONG - fails if var undefined when: my_variable == "value"
# CORRECT - check defined first when: my_variable is defined and my_variable == "value"
# Or use default when: (my_variable | default("")) == "value" ```
Order matters - check defined before using:
```yaml # WRONG - fails because undefined check comes after comparison when: my_variable == "value" and my_variable is defined
# CORRECT - check defined first when: my_variable is defined and my_variable == "value" ```
Step 4: Fix Comparison Operators
YAML has specific syntax requirements for comparisons:
```yaml # CORRECT comparison operators when: value == "string" when: value != "string" when: value > 10 when: value < 10 when: value >= 10 when: value <= 10
# WRONG in YAML when: value = "string" # Assignment, not comparison ```
For equality:
```yaml # String comparison when: ansible_os_family == "Debian"
# Numeric comparison when: port == 8080
# Boolean comparison when: enabled | bool ```
Step 5: Handle Multiple Conditions
Combine conditions with and, or:
```yaml # AND - both must be true when: ansible_os_family == "Debian" and ansible_distribution_version == "20.04"
# OR - either must be true when: ansible_os_family == "Debian" or ansible_os_family == "RedHat"
# Parentheses for complex logic when: (ansible_os_family == "Debian" and version == "20.04") or force_install ```
YAML lists for conditions:
# List acts as AND
when:
- ansible_os_family == "Debian"
- ansible_distribution_version == "20.04"Step 6: Fix Jinja2 Tests
Jinja2 tests use is:
```yaml # CORRECT - Jinja2 tests when: variable is defined when: variable is undefined when: variable is none when: variable is string when: variable is number when: path is exists when: path is directory when: path is file
# WRONG when: defined(variable) ```
Common tests:
```yaml # Check file exists when: "/etc/nginx/nginx.conf" is exists
# Check variable is truthy when: my_var is truthy
# Check variable in list when: item in ["web1", "web2"] ```
Step 7: Handle Registered Variable Conditions
Registered variables have specific structure:
```yaml - name: Check service command: systemctl is-active nginx register: service_status changed_when: false failed_when: false
- name: Start if not active
- service:
- name: nginx
- state: started
- when: service_status.rc != 0
`
Common registered checks:
```yaml # Check if task changed when: previous_task.changed
# Check if task succeeded when: previous_task is succeeded
# Check command output when: "'success' in result.stdout" when: result.stdout | search('pattern') ```
Step 8: Fix String Pattern Matching
Search strings in output:
```yaml # CORRECT - search in output when: "'error' in result.stdout"
# Using regex when: result.stdout | regex_search('pattern')
# WRONG when: result.stdout contains 'error' # 'contains' not valid ```
For regex:
when: result.stdout is search('pattern')
when: result.stdout is match('exact_pattern')Step 9: Handle List Conditions
Check items in lists:
```yaml # CORRECT when: item in my_list when: my_list | length > 0 when: my_list is not empty
# WRONG when: my_list.contains(item) # Python syntax not valid ```
For dictionary keys:
when: "'key' in my_dict"
when: my_dict.key is definedStep 10: Fix Numeric Comparisons
Numeric comparisons need proper types:
```yaml # CORRECT when: ansible_memtotal_mb > 1024 when: port | int == 8080
# WRONG - comparing string to int when: port == 8080 # If port is string "8080" ```
Convert types explicitly:
when: (value | int) > 100
when: (value | float) > 0.5Step 11: Handle Ansible Facts in Conditions
Facts provide system information:
```yaml # CORRECT - using facts when: ansible_os_family == "RedHat" when: ansible_distribution_version | version_compare('7.0', '>=') when: ansible_architecture == "x86_64"
# Check IPv4 address when: ansible_default_ipv4.address | ipaddr('192.168.1.0/24') ```
Step 12: Debug Condition Evaluation
See what's happening:
```yaml - name: Debug condition debug: msg: "ansible_os_family is {{ ansible_os_family }}" when: ansible_os_family is defined
- name: Show evaluated condition
- debug:
- msg: "Condition result: {{ ansible_os_family == 'Debian' }}"
`
Use verbose output:
ansible-playbook playbook.yml -vvLook for:
static condition: False
skipping: [webserver01]Quick Verification
Test condition behavior:
```yaml - hosts: localhost gather_facts: yes tasks: - name: Test condition debug: msg: "Condition met" when: ansible_os_family == "Debian"
- name: Show condition result
- debug:
- msg: "{{ ansible_os_family == 'Debian' }}"
`
Run it:
ansible-playbook test_condition.ymlPrevention Best Practices
- 1.Always check defined before using:
when: my_var is defined and my_var == "value"- 1.Use type conversion explicitly:
when: (value | int) > threshold
when: value | bool- 1.Quote string comparisons:
when: ansible_os_family == "Debian"- 1.Use parentheses for complex logic:
when: (a == "x" and b == "y") or c- 1.Debug conditions before relying on them:
- debug:
var: my_condition_variable
- debug:
msg: "{{ my_condition_variable == 'expected' }}"Condition evaluation errors come from undefined variables, type mismatches, or Jinja2 syntax issues. Check variable existence, convert types explicitly, and debug condition results before relying on task execution.