changelogs/CHANGELOG-v2.21.rst
.. contents:: Topics
| Release Date: 2026-04-21
| Porting Guide <https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>__
invocation task result key by default. Injection of the invocation task result key for Python and Powershell modules may be enabled with the var-settable INJECT_INVOCATION config item. Most callbacks mask invocation when displaying a task or loop item result.WORKER_SESSION_ISOLATION config item can be set to false (via variable/config/envvar) to disable forked worker session isolation.rc key and absence of a failed key will be deprecated in Ansible Core 2.22. Actions and modules must explicitly communicate failure by setting the failed key, using APIs that do so, or raising an unhandled exception. In future releases, the rc key will receive no special handling during task result processing.--controller and --target are properly resolved for remote. Previously, remote alias values (e.g. fedora/latest) resolved to the correct name only for the legacy --remote arg, failing with an unknown image error for the newer args.invocation item result key omitted from registered values for looped task results, unless enabled via INJECT_INVOCATION. Previously, it was deleted from registered non-loop results and only available to callbacks.| Release Date: 2026-04-13
| Porting Guide <https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>__
dist_info when running tests.validate_argspec when tags are defined on the play. The always tag is only added if the play has no tags.--start-at-task - fix starting at the requested task instead of starting at the next block or play. Play level tasks run first. (https://github.com/ansible/ansible/issues/86268)| Release Date: 2026-04-06
| Porting Guide <https://docs.ansible.com/ansible-core/2.21/porting_guides/porting_guide_core_2.21.html>__
ansible-galaxy install and ansible-galaxy collection install|download - collections that declare a requires_ansible version that is not compatible with the running ansible-core version are now excluded from installation and download by default. In previous versions, ansible-galaxy would install such collections even if doing so resulted in an error at load time. To restore the previous behavior, set COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH to ignore in your configuration. (https://github.com/ansible/ansible/issues/78539)register_host_variables method on ActionBase. Previously, variable registration could only be simulated by user action plugins by returning ansible_facts with insecure fact injection.register task keyword allows mapping multiple variable names to Jinja expressions to transform task results and other variables. The mapping form can replace many usages of set_fact and allows order-independent chained access to other variable expressions within the same task._task implicit object is available for use in register and task conditional expressions (e.g., failed_when). The result of the current task can be accessed via the _task.result property, without the use of register. Under a loop, _task.result is the most recently completed result and _task.loop_result provides access to accumulated loop results. The _task.polymorphic_result property provides compatibility with classic name-only register in loops. The value is the result of the most recent loop iteration, then becomes the final list loop result once the loop is complete.DataLoader to deal exclusively in strpwsh interpreter and can access the same module utils that Windows PowerShell modules can use. Some PowerShell based module utils may not be compatible due to their reliance on Windows APIs but Ansible.Basic.cs for module input and output handling works.DISPLAY_TRACEBACK contains error or always. In the past the debug information would have been included if -vvv or higher was used but this new behavior aligns the logic with the new option added in Ansible 2.19.setuptools version is now 77.0.3, as it is needed for the new PEP 639 license formatimportunwanted rule for the pylint sanity test. It now includes various os.* and subprocess.* subprocess functions in Ansible modules and module_utils.use-run-command-not-popen and use-run-command-not-os-call error codes from the validate-modules sanity test. These scenarios are now covered by the pylint sanity test.urllib2 usage.parallels managed macOS provider with a new mac provider..winrm and .networking as valid JSON/YAML inventory file extensions. This should not affect any public facing code as it is used internally for inventories generated by ansible-test.ansible-vault edit.break_when_result key is always present in results when a break_when expression is used.break_when_suppressed_exception key is added to a result when a break_when expression fails and masks an existing exception in a result.break_when expression now preserves the loop structure of a result and any loop item results.changed_when_result key is always present in results when a changed_when expression is used.changed_when_suppressed_exception key is added to a result when a changed_when expression fails and masks an existing exception in a result.ActionBase._low_level_execute_command method no longer adds && sleep 0 to commands. This was a work-around for a 10+ year old Linux kernel bug affecting OpenSSH. By August of 2016 the fix had been included in kernel versions 4.1.26, 4.4.12, 4.5.6, 4.6.1 and 4.7. Linux kernel bug report: https://lore.kernel.org/lkml/[email protected]/ OpenSSH bug report: https://bugzilla.mindrot.org/show_bug.cgi?id=2492display_included_hosts option to control the included: banner lines for include_tasks/include_role (https://github.com/ansible/ansible/issues/84499).display_skipped_hosts (https://github.com/ansible/ansible/issues/84469).ignore_errors will always be treated as Falseignore_errors keyword behave more consistently in looped tasks. If ignore_errors resolves True for any loop item, errors will be ignored for the entire task.ignore_unreachable keyword behave more consistently in looped tasks. If ignore_unreachable resolves True for any loop item, unreachable hosts will be ignored for the entire task.rescuable to allow it to toggle between task failure and syntax errors.break_when keyword is now validated when the value is falsey.skipped key when it would be False.results key returned from an action or module is always preserved. Previously the results key was sometimes removed, depending on the type of its value.crypt implementation from the C library used to build Python, or with expanded functionality using libxcryptcertificate_key_password option through the variable ansible_psrp_certificate_key_password that can be used to decrypt the key specified by certificate_key_pem. This option requires pypsrp>=0.9.0 to be installed in the Ansible environment.no_profile option through the variable ansible_psrp_no_profile that can stop the remote Windows host from loading the user profile on the Ansible tasks. This option requires pypsrp>=0.9.0 to be installed in the Ansible environment.decrypt argument from the module documentation (https://github.com/ansible/ansible/issues/86067).vault_behavior argument to configure how vaulted values are rendered.negotiate_service used to build the Kerberos Service Principal Name from WSMAN to host. This aligns the defaults to how the native PowerShell PSRemoting client works on Windows and ensures that Kerberos can be used by more Windows targets by default. No deprecation period is used for this change as host is a builtin SPN to Windows and should improve compatibility out of the box. To go back to the old behaviour for any reason, set ansible_psrp_negotiate_service=WSMAN in the host vars.get_all_subclasses() function from ansible.module_utils.basic is deprecated and will be removed in ansible-core 2.24. Use get_all_subclasses() from ansible.module_utils.common._utils instead.get_platfrom() function from ansible.module_utils.basic is deprecated and will be removed in ansible-core 2.24. Use platform.system() from the Python standard library instead.load_platform_subclass() function from ansible.module_utils.basic is deprecated and will be removed in ansible-core 2.24. Use get_platform_subclass() from ansible.module_utils.common.sys_info instead.PluginLoader - Deprecate unused aliases attribute. Plugins in a collection should define aliases in the meta/runtime.yml file using the redirect field instead.ansible.module_utils.six - The six compatibility library provided at ansible.module_utils.six is deprecated, and planned for removal in ansible-core 2.24has_native_async and always_pipeline_modules. Connection plugins that wish to apply custom behaviour around pipelining should instead override the method is_pipelining_enabled(self, wrap_async=False) added in Ansible 2.19. For backwards compatibility no runtime deprecation warning is emitted but will be in the future.ansible.builtin.paramiko connection plugin (https://github.com/ansible/ansible/issues/86002). Setting the connection keyword to persistent or smart no longer attempts to use paramiko.ansible.module_utils.compat.paramiko (https://github.com/ansible/ansible/issues/86001).handle_stats_and_callbacks parameter of the StrategyBase._load_included_file method. (https://github.com/ansible/ansible/issues/86003)datetime, signal, types, chain, repeat, map and shlex_quote from ansible.module_utils.basic.safe_eval function (#85996) (#85999)AnsibleModule.human_to_bytes(), which was never adjusted after the standalone human_to_bytes() got a new parameter default_unit (https://github.com/ansible/ansible/pull/85259).async tasks (https://github.com/ansible/ansible/issues/86491)powershell shell commands when using a connection plugin that does not support stdin/pipeline input - https://github.com/ansible/ansible/issues/86397_make_tmp_path error to only include the command run rather than the shell's dataclass repr from mkdtemp.ansible-galaxy collection list - issue a warning when a collection's namespace and name do not match its filepath. (https://github.com/ansible/ansible/issues/69813)ansible-galaxy collection list|install - list collections based on reference (the fqcn used to refer to them in a playbook), not based on their documented name. (https://github.com/ansible/ansible/issues/69813)ansible-galaxy collection verify - fail collection verification when a collection's namespace and name do not match its filepath. (https://github.com/ansible/ansible/issues/69813)ansible-galaxy install/ansible-galaxy collection download - collections from git repositories with a tag or sha version no longer emit detached head warning messages (https://github.com/ansible/ansible/issues/86169).ansible.builtin.pip - Running the built-in pip module with check_mode and packages coming from VCS URLs, archives, or local filepaths now correctly outputs the changed status of the task. Previously, it was always reported as changed due to improper package name resolution. (https://github.com/ansible/ansible/pull/85623)ansible, ansible-console - fix executing - meta: end_play tasks.JsonRpcServer.validate_certs when downloading collections. (https://github.com/ansible/ansible/issues/86694)X.0.0, while the collection's version is X.0.0-prerelease (https://github.com/ansible/ansible/issues/85193)."expat during provisioning of Fedora 42 remote instances.env --list-files option, non-filename output is now sent to stderr.run_command() attempts to parse a command with broken syntax passed in as a string (https://github.com/ansible/ansible/issues/85719).TaskResult.task.connection properly reflects the loaded connection name used. Previously, incorrect values were reported in some cases.changed used to be false even when the source was actually copied. It now makes sure changed is true in this case. (https://github.com/ansible/ansible/issues/85833)Install-Python-Debian from files outputted by the deb822_repository module (https://github.com/ansible/ansible/issues/86395)getuser fallback error handling on Python 3.13 and later. (https://github.com/ansible/ansible/issues/86142)libgcc.i686) where a different architecture of the same package is already installed (https://github.com/ansible/ansible/issues/86156).files directory when the task action cannot be resolved (https://github.com/ansible/ansible/issues/85655).version supplied is an invalid ref (https://github.com/ansible/ansible/issues/51580)match argument have been automatically imported by other module arguments such as uid_owner and prevents duplicate extension imports which previously caused an error (https://github.com/ansible/ansible/issues/84387).getuser fallback error handling on Python 3.13 and later.-e to pip when the editable and requirements parameters are both used.editable=True, ensure each package is editable (https://github.com/ansible/ansible/issues/77755).when, until, failed_when) always causes the task to report a descriptive failure while preserving the task result. The resulting task failure is always recoverable via ignore_errors. Previous inconsistent error handling in task conditionals could result in warnings, loss of completed task results, recoverable task errors, unrecoverable task errors, or failure of the Ansible controller process.deepcopy on an imported template (https://github.com/ansible/ansible/issues/86723).!vault-tagged ciphertext.user module integration tests can now run multiple times on the same freebsd host (https://github.com/ansible/ansible/issues/86541).seuser parameter is set on a system where SELinux is not enabled, instead of silently ignoring it (https://github.com/ansible/ansible/issues/85542).FreeBsdUser to not create /nonexistent directory when modifying user to add them to a group on FreeBSD (https://github.com/ansible/ansible/issues/86368)UPN) but the pykerberos library is not installed so Kerberos is unavailable.