Introduction
The literal-compare rule (601) in ansible-lint flags redundant comparisons to True or False in when conditions. While technically correct, these comparisons add noise without value — and can introduce subtle bugs with string-to-boolean conversion.
The Error
# ⚠️ Triggers literal-compare warning
- name: Run only in production
ansible.builtin.debug:
msg: "Production task"
when: production == True
$ ansible-lint playbook.yml
literal-compare: Don't compare to literal True/False.
playbook.yml:5 Task/Handler: Run only in production
The Fix
# ✅ Clean — directly evaluate the boolean
- name: Run only in production
ansible.builtin.debug:
msg: "Production task"
when: production
For negative conditions:
# ❌ Redundant
when: debug_mode == False
# ✅ Clean
when: not debug_mode
Why It Matters
1. Readability
# Verbose and redundant
when: is_enabled == True and is_configured == True
# Clear and concise
when: is_enabled and is_configured
2. Avoid String/Boolean Bugs
Variables from inventory or extra-vars may be strings, not booleans:
ansible-playbook site.yml -e "production=true"
# production is the STRING "true", not boolean True
# ⚠️ BUG: "true" (string) != True (boolean)
when: production == True # This is FALSE!
# ✅ Works: Jinja2 evaluates "true" as truthy
when: production
# ✅ Safest: explicitly convert to bool
when: production | bool
3. Consistency
Following lint rules ensures all team members write conditions the same way.
Common Patterns
Simple Boolean
# ❌ Don't
when: enable_ssl == True
when: enable_ssl == False
# ✅ Do
when: enable_ssl
when: not enable_ssl
Boolean with bool Filter
# When variable might be a string ("true"/"false"/"yes"/"no")
when: enable_feature | bool
when: not (skip_tests | bool)
Compound Conditions
# ❌ Don't
when: is_production == True and ssl_enabled == True
# ✅ Do
when: is_production and ssl_enabled
# ✅ With bool filter for safety
when: is_production | bool and ssl_enabled | bool
Comparing to Specific Values (NOT Affected)
These are fine — the rule only applies to True/False literals:
# ✅ These are legitimate comparisons
when: env == "production"
when: ansible_os_family == "RedHat"
when: count | int > 5
when: status == "active"
Testing for None/Undefined
# ✅ Check if defined
when: my_var is defined
# ✅ Check if not none
when: my_var is not none
# ✅ Check truthiness with default
when: my_var | default(false) | bool
is sameas Test (Strict Identity Check)
If you truly need to distinguish True from truthy:
# Strict boolean identity check (rare)
when: my_var is sameas true
when: my_var is sameas false
This passes lint and tests identity, not equality. Use only when you need to distinguish True from 1 or "yes".
Suppressing the Rule
If you have a legitimate reason:
# Per-task skip
- name: Strict check needed
ansible.builtin.debug:
msg: "Exact boolean required"
when: flag == True # noqa: literal-compare
# Per-file in .ansible-lint
skip_list:
- literal-compare
Quick Reference
| Instead of | Write |
|---|---|
when: x == True | when: x |
when: x == False | when: not x |
when: x != True | when: not x |
when: x != False | when: x |
when: x == True and y == True | when: x and y |
| String variable | when: x | bool |
Related Articles
- Ansible-Lint Guide
- Ansible Ternary Filter
- Ansible Best Practices Guide
- syntax-check Rule (911)
- no-log-password Rule
Conclusion
Replace when: x == True with when: x and when: x == False with when: not x. Use | bool when variables might be strings from inventory or extra-vars. The rule improves readability, prevents string/boolean comparison bugs, and keeps conditions consistent across your playbooks.