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 12 Upgrade Guide: Breaking Changes, Data Tagging & What to Test First

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

Complete Ansible 12 upgrade guide covering breaking changes in ansible-core 2.19, the new Data Tagging system, broken conditionals enforcement, multi-pass.

Ansible 12 ships with ansible-core 2.19, bringing the biggest internal change in years: a complete templating system overhaul and the new Data Tagging feature. These changes improve security and performance but introduce breaking changes that will affect many existing playbooks.

This guide walks through every breaking change, shows you what breaks and how to fix it, and gives you a pre-upgrade testing checklist.

What's New in Ansible 12 / ansible-core 2.19

| Feature | Impact | Action Required | |---------|--------|----------------| | Data Tagging | New metadata tracking for template data | Test playbooks — may expose hidden bugs | | Broken Conditionals | Non-boolean conditionals now error | Fix when/assert statements | | Multi-pass Templating Removed | Nested {{ }} in expressions blocked | Remove template delimiters from expressions | | Stricter Jinja2 Evaluation | Order-of-operations bugs now caught | Add parentheses where needed | | ALLOW_BROKEN_CONDITIONALS | Temporary escape hatch | Use for transition, don't rely on it |

See also: Ansible 13 Upgrade Guide: Breaking Changes, Removals, and Migration Steps

Pre-Upgrade Checklist

Before upgrading production systems:

# 1. Check current version
ansible --version
ansible-core --version

# 2. Create a virtualenv for testing python3 -m venv ~/ansible12-test source ~/ansible12-test/bin/activate pip install ansible==12.0.0

# 3. Run playbooks in check mode first ansible-playbook site.yml --check -v

# 4. Enable broken conditionals warning (don't error) export ANSIBLE_ALLOW_BROKEN_CONDITIONALS=true ansible-playbook site.yml --check -v 2>&1 | grep -i "broken conditional\|warning"

Breaking Change 1: Broken Conditionals

This is the change that will affect the most playbooks. ansible-core 2.19 now requires conditionals to return actual booleans, not truthy values.

What Breaks

# ❌ BREAKS in Ansible 12 — truthy string, not boolean
- name: Check hostname
  ansible.builtin.assert:
    that: inventory_hostname

# Error: Conditional result was 'myhost' of type 'str', # which evaluates to True. Conditionals must have a boolean result.

How to Fix

# ✅ WORKS — explicit boolean result
- name: Check hostname is set
  ansible.builtin.assert:
    that: inventory_hostname | length > 0

# ✅ Also works — use 'is defined' or 'is truthy' - name: Check hostname is defined ansible.builtin.assert: that: inventory_hostname is defined

Common Patterns That Break

# ❌ Truthy check on registered variable
- name: Run command
  ansible.builtin.command: whoami
  register: result

- name: Check result ansible.builtin.debug: msg: "Success" when: result.stdout # Fix → when: result.stdout | length > 0

# ❌ Accidental string in assert - name: Bad assert ansible.builtin.assert: that: inventory_hostname is defined and 'inventory_hostname | length > 0' # Fix → remove quotes: inventory_hostname is defined and inventory_hostname | length > 0

# ❌ Dictionary as conditional (YAML parsing trap) - name: Check message ansible.builtin.assert: that: - result.msg == "some_key: some_value" # Fix → quote the whole expression: # - 'result.msg == "some_key: some_value"'

# ❌ Jinja operator precedence - name: Contains check ansible.builtin.assert: that: inventory_hostname is contains "local" ~ "host" # Fix → add parentheses: # that: inventory_hostname is contains("local" ~ "host")

Temporary Escape Hatch

If you need time to fix all your playbooks:

# ansible.cfg
[defaults]
allow_broken_conditionals = true

Or as environment variable:

export ANSIBLE_ALLOW_BROKEN_CONDITIONALS=true

Warning: This reduces errors to warnings. It's a migration aid, not a permanent solution. Fix your conditionals.

See also: ansible-core 2.19 Templating Changes: Fix Broken Conditionals & Jinja Errors

Breaking Change 2: Multi-Pass Templating Removed

ansible-core 2.19 no longer allows nested templates or template delimiters inside expressions. This prevents untrusted templates from being executed — a security improvement.

What Breaks

# ❌ BREAKS — template delimiters inside expression
- name: Calculate value
  ansible.builtin.assert:
    that: 1 + {{ value }} == 2
  vars:
    value: 1

# Error: Syntax error in expression. Template delimiters are not # supported in expressions: expected token ':', got '}'

How to Fix

# ✅ WORKS — reference variable directly
- name: Calculate value
  ansible.builtin.assert:
    that: 1 + value == 2
  vars:
    value: 1

More Examples

# ❌ BREAKS — dynamic template construction
- name: Dynamic conditional
  ansible.builtin.debug:
    msg: "Dynamic"
  when: "{{ my_condition }}"
  # Fix → when: my_condition

# ❌ BREAKS — nested template in variable - name: Nested template ansible.builtin.debug: msg: "Value is {{ '{{ inner_var }}' }}" # Fix → msg: "Value is {{ inner_var }}"

# ❌ BREAKS — template in loop expression - name: Loop with template ansible.builtin.debug: msg: "{{ item }}" loop: "{{ {{ my_list }} }}" # Fix → loop: "{{ my_list }}"

Breaking Change 3: Stricter Expression Syntax

Syntax errors that were previously silently ignored now produce errors.

# ❌ BREAKS — trailing comma (syntax error)
- name: Compare values
  ansible.builtin.assert:
    that: 1 == 2,
# Error: Syntax error in expression: chunk after expression
# Fix → remove the trailing comma: that: 1 == 2

See also: AAP 2.6 Migration from AWX: Complete Upgrade and Data Migration Guide

Data Tagging: What It Is

Data Tagging is the new internal mechanism that tracks metadata about template data as it flows through Ansible. It's what enables all the stricter checking above.

What it means for you: • Variables now carry metadata about their origin and type • Ansible can detect when untrusted data enters templates • Conditional evaluation is type-checked at runtime • Previously silent bugs are now surfaced

You don't need to change anything for Data Tagging itself — it's the enforcement mechanisms (broken conditionals, multi-pass removal) that require playbook changes.

Step-by-Step Upgrade Process

Step 1: Audit Your Playbooks

# Find potential broken conditionals
grep -rn "when:" roles/ playbooks/ | grep -v "is defined\|is not defined\|==\|!=\|>.*<\|in \|not in\|is true\|is false\|bool"

# Find nested templates grep -rn "{{ {{ \|{{ '{{" roles/ playbooks/

# Find template delimiters in when/assert grep -rn "when: \"{{ \|that: .* {{ " roles/ playbooks/

Step 2: Test in Staging

# test-upgrade.yml — Run against staging
- name: Test Ansible 12 compatibility
  hosts: staging
  gather_facts: true
  tasks:
    - name: Verify version
      ansible.builtin.debug:
        msg: "Running ansible-core {{ ansible_version.full }}"

- name: Test boolean conditional ansible.builtin.debug: msg: "Boolean conditionals work" when: ansible_os_family == "Debian"

- name: Test explicit length check ansible.builtin.assert: that: - inventory_hostname | length > 0 - ansible_distribution is defined

Step 3: Fix and Validate

# Run with verbose output to catch warnings
ansible-playbook site.yml --check -vv 2>&1 | tee upgrade-check.log

# Count issues grep -c "broken conditional\|Syntax error\|Template delimiters" upgrade-check.log

Step 4: Upgrade Production

# Upgrade
pip install --upgrade ansible==12.0.0

# Verify ansible --version # ansible [core 2.19.x]

# Run smoke test ansible-playbook smoke-test.yml

Version Compatibility Matrix

| Ansible Package | ansible-core | Python | Status | |----------------|-------------|--------|--------| | Ansible 12 | 2.19.x | 3.11+ | Current | | Ansible 11 | 2.18.x | 3.10+ | Maintained | | Ansible 10 | 2.17.x | 3.10+ | Security fixes | | Ansible 9 | 2.16.x | 3.10+ | EOL |

FAQ

What is Data Tagging in ansible-core 2.19?

Data Tagging is a new internal feature that tracks metadata about template data as it flows through Ansible. It enables stricter type checking on conditionals, prevents untrusted template execution, and surfaces bugs that previous versions silently ignored. You don't interact with Data Tagging directly — it powers the improved enforcement behind the scenes.

Will my existing playbooks break when upgrading to Ansible 12?

Possibly. The most common breakage is conditionals that rely on truthy evaluation instead of explicit boolean results. Use ALLOW_BROKEN_CONDITIONALS=true as a temporary migration aid, audit your playbooks with grep, and test in staging before upgrading production.

What is ALLOW_BROKEN_CONDITIONALS?

A configuration option in ansible-core 2.19 that temporarily reduces broken conditional errors to warnings. Set it in ansible.cfg or as an environment variable to buy time for migration. It's a transition tool — don't leave it enabled permanently.

How do I find all broken conditionals in my playbooks?

Search for when: and that: clauses that don't use explicit boolean operators (==, !=, is defined, is true/false, | bool, | length > 0). Run your playbooks with --check -vv on ansible-core 2.19 to get specific error messages for each broken conditional.

Can I run Ansible 11 and 12 side by side?

Yes — use Python virtualenvs. Create separate environments for each version and switch between them for testing. This is the recommended approach for migration.

Conclusion

Ansible 12 with ansible-core 2.19 is a significant upgrade that improves security and catches real bugs in your playbooks. The breaking changes — strict boolean conditionals and multi-pass templating removal — require attention, but every fix makes your automation more reliable. Test in staging, fix your conditionals, and upgrade with confidence.

Related Articles

ansible-core 2.19 Templating ChangesAnsible Conditionals: when, assert & Conditional ExecutionAnsible Jinja2 Filters Complete ReferenceAnsible Check Mode / Dry Run Guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home