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

FeatureImpactAction Required
Data TaggingNew metadata tracking for template dataTest playbooks — may expose hidden bugs
Broken ConditionalsNon-boolean conditionals now errorFix when/assert statements
Multi-pass Templating RemovedNested {{ }} in expressions blockedRemove template delimiters from expressions
Stricter Jinja2 EvaluationOrder-of-operations bugs now caughtAdd parentheses where needed
ALLOW_BROKEN_CONDITIONALSTemporary escape hatchUse for transition, don't rely on it

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"

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

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.

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 }}"

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

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

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.

See also: AAP 2.7 Upgrade Path: RPM Installer Removed, Containerized-Only, and the Mandatory 2.6 Stepping Stone

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 Packageansible-corePythonStatus
Ansible 122.19.x3.11+Current
Ansible 112.18.x3.10+Maintained
Ansible 102.17.x3.10+Security fixes
Ansible 92.16.x3.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.

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home