Ansible 13 Upgrade Guide: Breaking Changes, Removals, and Migration Steps
By Luca Berton · Published 2024-01-01 · Category: installation
Complete Ansible 13 upgrade guide covering all breaking changes in ansible-core 2.20. Python 3.12+ required, INJECT_FACTS_AS_VARS deprecated, failed_when exception key renamed, PowerShell quote stripping removed, smart transport gone, and collection-level breaking changes with migration examples.
Ansible 13 is based on ansible-core 2.20. The biggest changes: Python 3.12+ required on controllers, Python 3.9+ on targets, INJECT_FACTS_AS_VARS deprecated, and the failed_when exception key renamed. Here's everything you need to update before upgrading.
Prerequisites
Python Version Requirements
| Component | Ansible 12 (core 2.19) | Ansible 13 (core 2.20) | |-----------|----------------------|----------------------| | Controller | Python 3.11+ | Python 3.12+ | | Target hosts | Python 3.8+ | Python 3.9+ |
This is the most common upgrade blocker — ensure all controller nodes run Python 3.12+.
Upgrade Path
Always upgrade through Ansible 12 first. The ansible-core 2.19 templating changes (introduced in Ansible 12) are prerequisites for Ansible 13.
Breaking Changes in ansible-core 2.20
1. INJECT_FACTS_AS_VARS Deprecated
The biggest behavioral change. Currently, Ansible injects facts as top-level variables (ansible_distribution) AND stores them in the ansible_facts dictionary (ansible_facts['distribution']). The top-level injection is deprecated and will be removed in ansible-core 2.24.
Important: Inside ansible_facts, the ansible_ prefix is removed:
| Old (deprecated) | New (recommended) | |-------------------|-------------------| | ansible_distribution | ansible_facts['distribution'] | | ansible_os_family | ansible_facts['os_family'] | | ansible_hostname | ansible_facts['hostname'] | | ansible_default_ipv4 | ansible_facts['default_ipv4'] | | ansible_memtotal_mb | ansible_facts['memtotal_mb'] | | ansible_processor_vcpus | ansible_facts['processor_vcpus'] |
To silence warnings now (while migrating):
Migration strategy: Search your playbooks for ansible_ variables and update them. This is the highest-effort change in Ansible 13.
2. failed_when Exception Key Renamed
When you use failed_when: false to suppress errors, the exception key in the result has been renamed:
3. PowerShell Quote Stripping Removed
Windows module utilities no longer automatically remove quotes from paths:
4. smart Transport Removed
The DEFAULT_TRANSPORT = smart option (which auto-selected ssh or paramiko) has been removed:
5. DataLoader.get_basedir Returns Absolute Path
If you write custom plugins that use DataLoader.get_basedir(), it now returns an absolute path instead of relative. Update any path manipulation code accordingly.
6. Argument Spec: None Treated as Empty String
None values are now treated as empty strings for the str type in argument spec validation. This improves consistency with pre-2.19 templating conversions but may affect custom modules that rely on None vs "" distinction.
Removed Features
These previously deprecated features are now gone:
| Removed | Replacement | |---------|-------------| | vault/unvault filter vaultid param | Use vault_id instead | | Galaxy v2 server API | Galaxy servers must support v3 | | dnf/dnf5 install_repoquery option | Remove from playbooks | | encrypt module passlib_or_crypt API | Use updated API | | paramiko PARAMIKO_HOST_KEY_AUTO_ADD | Use SSH config | | paramiko PARAMIKO_LOOK_FOR_KEYS | Use SSH config | | yum_repository keepcache option | Remove from playbooks | | Vars plugins get_host_vars/get_group_vars fallback | Inherit from BaseVarsPlugin |
Collection-Level Breaking Changes
community.mysql
community.vmware
community.general
community.docker
awx.awx
The awx.awx collection will be removed from Ansible 14 due to ongoing refactoring. Plan your migration:
include_vars Changes
Two breaking changes for include_vars:
replace Module: Unicode Mode
The replace module now reads files as unicode instead of bytes:
Pre-Upgrade Checklist
FAQ
Can I skip Ansible 12 and go straight to 13?
Not recommended. Ansible 12 (core 2.19) introduced major templating changes that surface issues in playbooks. Upgrading through 12 first lets you fix those issues before adding the Ansible 13 changes on top.
How long until INJECT_FACTS_AS_VARS is fully removed?
The deprecation targets ansible-core 2.24 (approximately Ansible 17). You have several major versions to migrate, but starting now avoids a painful bulk migration later.
Will my roles from Ansible Galaxy still work?
Most will, but roles that use deprecated fact syntax (ansible_distribution vs ansible_facts['distribution']) will show deprecation warnings. Roles that use removed features (vault vaultid, smart transport) will break.
What about Execution Environments?
Update your EE container images to include Python 3.12+ and the latest collection versions. If your EE uses community.vmware, switch from pyvmomi to vcf-sdk.
Conclusion
Ansible 13's biggest changes are Python 3.12+ requirement and INJECT_FACTS_AS_VARS deprecation. Start migrating fact variable syntax now — it's the highest-effort change. Fix failed_when exception keys, remove smart transport, and update collection dependencies. Always upgrade through Ansible 12 first.
Related Articles • Ansible 12 Upgrade Guide • ansible-core 2.19 Templating Changes • Ansible facts: Gather, Use, Create • Ansible Variable Precedence Guide
Category: installation