Summary
In ansible-core 2.21.0, when a play declares its connection using the short name (e.g. connection: local, not connection: ansible.builtin.local), the magic variable ansible_connection reports the declared short name (local) on the first iteration of a looped task and the connection
plugin's FQCN (ansible.builtin.local) on every subsequent iteration of the same task. The variable mutates inside a single task without anything in the playbook changing the connection.
The same playbook is unaffected on ansible-core 2.20.6 — there, ansible_connection reports the declared short name on every iteration.
Any Jinja expression in the codebase that compares ansible_connection against a short name (e.g. {{ ... if ansible_connection == 'local' else ... }}) silently flips its result on iterations 2+ after upgrading to 2.21.0. No deprecation in 2.19 or 2.20 warned about this; the only related
entry in the 2.21.0 changelog is "callbacks - The value of TaskResult.task.connection properly reflects the loaded connection name used. Previously, incorrect values were reported in some cases.", which is scoped to callbacks and does not announce a change to the user-templatable
ansible_connection variable.
Issue Type
Bug Report
Component Name
core
Ansible Version
$ ansible --version
ansible [core 2.21.0]
python version = 3.12.3
jinja version = 3.1.6
Configuration
# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t all
CONFIG_FILE() = None
GALAXY_SERVERS:
OS / Environment
Ubuntu 24.04 (x86_64)
Steps to Reproduce
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- debug:
msg: "iter {{ item }}: ansible_connection={{ ansible_connection }}"
loop: [1, 2, 3, 4]
Expected Results
All four iterations print ansible_connection=local, matching the play's declared connection: local. This is what ansible-core 2.20.6 does:
ok: [localhost] => (item=1) => { "msg": "iter 1: ansible_connection=local" }
ok: [localhost] => (item=2) => { "msg": "iter 2: ansible_connection=local" }
ok: [localhost] => (item=3) => { "msg": "iter 3: ansible_connection=local" }
ok: [localhost] => (item=4) => { "msg": "iter 4: ansible_connection=local" }
Actual Results
ok: [localhost] => (item=1) => { "msg": "iter 1: ansible_connection=local" }
ok: [localhost] => (item=2) => { "msg": "iter 2: ansible_connection=ansible.builtin.local" }
ok: [localhost] => (item=3) => { "msg": "iter 3: ansible_connection=ansible.builtin.local" }
ok: [localhost] => (item=4) => { "msg": "iter 4: ansible_connection=ansible.builtin.local" }
# The variable's value changes inside one task — short name on iteration 1, FQCN on iterations 2+ — even though nothing in the playbook touches the connection between iterations.
Code of Conduct
Summary
In ansible-core 2.21.0, when a play declares its connection using the short name (e.g.
connection: local, notconnection: ansible.builtin.local), the magic variableansible_connectionreports the declared short name (local) on the first iteration of a looped task and the connectionplugin's FQCN (
ansible.builtin.local) on every subsequent iteration of the same task. The variable mutates inside a single task without anything in the playbook changing the connection.The same playbook is unaffected on ansible-core 2.20.6 — there,
ansible_connectionreports the declared short name on every iteration.Any Jinja expression in the codebase that compares
ansible_connectionagainst a short name (e.g.{{ ... if ansible_connection == 'local' else ... }}) silently flips its result on iterations 2+ after upgrading to 2.21.0. No deprecation in 2.19 or 2.20 warned about this; the only relatedentry in the 2.21.0 changelog is "callbacks - The value of
TaskResult.task.connectionproperly reflects the loaded connection name used. Previously, incorrect values were reported in some cases.", which is scoped to callbacks and does not announce a change to the user-templatableansible_connectionvariable.Issue Type
Bug Report
Component Name
core
Ansible Version
Configuration
OS / Environment
Ubuntu 24.04 (x86_64)
Steps to Reproduce
Expected Results
All four iterations print
ansible_connection=local, matching the play's declaredconnection: local. This is what ansible-core 2.20.6 does:Actual Results
Code of Conduct