# interpolation of loop variables

**URL:** <https://forum.ansible.com/t/interpolation-of-loop-variables/38715>\
**Category:** Ansible Project\
**Created:** [March 13, 2024, 6:27pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715 "2024-03-13T18:27:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [March 13, 2024, 6:27pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/1 "2024-03-13T18:27:17Z")

</div>

Hi all - I recently upgraded to Ansible core 2.15, and started hitting “Conditional is marked as unsafe, and cannot be evaluated.” As discussed at [https://docs.ansible.com/ansible/latest/porting\_guides/porting\_guide\_9.html](https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_9.html), I removed templating from when and assert. All seemed fine, but then I discovered loop variables don’t appear to be interpolated in assert without templating.

As an example, consider the following playbook that aims to confirm two variables, varA and varB, are defined (in the sample output, they are not defined):  
#\> cat b.yml

---

<div class="post-metadata">

**Author:** ![utoddl](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/utoddl/32/249_2.png) [@utoddl](https://forum.ansible.com/u/utoddl)\
**Post date:** [March 13, 2024, 8:55pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/2 "2024-03-13T20:55:30Z")

</div>

Maybe it will facilitate understanding what’s going on if we name things what they really are:

```auto
---
- hosts: localhost
  gather_facts: no
  tasks:
  - name: Strings in a loop are indeed defined
    ignore_errors: true
    assert:
      that: item is defined
    loop:
      - RandomStringA
      - RandomStringB
      - ansible_forks

  - name: Strings in a loop are unlikely to be variable names
    ignore_errors: true
    assert:
      that: '{{ item }} is defined'
    loop:
      - UndefinedVariableNameA
      - UndefinedVariableNameB
      - ansible_forks

```

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [March 14, 2024, 11:48am UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/3 "2024-03-14T11:48:22Z")

</div>

I sense that “with templating” does as expected?

**% ansible --version**

ansible [core 2.16.4]

config file = None

configured module search path = [‘/Users/wrowe/.ansible/plugins/modules’, ‘/usr/share/ansible/plugins/modules’]

ansible python module location = /opt/homebrew/lib/python3.11/site-packages/ansible

ansible collection location = /Users/wrowe/.ansible/collections:/usr/share/ansible/collections

executable location = /opt/homebrew/bin/ansible

python version = 3.11.8 (main, Feb 6 2024, 21:21:21) [Clang 15.0.0 (clang-1500.1.0.2.5)] (/opt/homebrew/opt/python@3.11/bin/python3.11)

jinja version = 3.1.3

libyaml = True

**% ansible-playbook foo.yaml -i localhost,**

PLAY [localhost] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

TASK [without templating] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

ok: [localhost] =\> (item=varA) =\> {

“ansible\_loop\_var”: “item”,

“changed”: false,

“item”: “varA”,

“msg”: “All assertions passed”

}

ok: [localhost] =\> (item=varB) =\> {

“ansible\_loop\_var”: “item”,

“changed”: false,

“item”: “varB”,

“msg”: “All assertions passed”

}

TASK [with templating] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

failed: [localhost] (item=varA) =\> {

“ansible\_loop\_var”: “item”,

“assertion”: “varA is defined”,

“changed”: false,

“evaluated\_to”: false,

“item”: “varA”,

“msg”: “Assertion failed”

}

failed: [localhost] (item=varB) =\> {

“ansible\_loop\_var”: “item”,

“assertion”: “varB is defined”,

“changed”: false,

“evaluated\_to”: false,

“item”: “varB”,

“msg”: “Assertion failed”

}

PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Walter

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [March 14, 2024, 2:11pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/4 "2024-03-14T14:11:56Z")

</div>

Hey Todd - apologies, I don’t understand your comment.

Hey Walter - yes, you are correct.

To elaborate on the use case. FIrst task in my playbooks confirms the user provided all the expected/required variables. I iterate over the list of variables and make sure they are defined with assert. The list of required variables is provided as a list to “loop.” Trouble I’m seeing is the items in the loop (i.e., the variable names) are not being interpolated by assert unless they are templated.

But if we ignore the loop for a second, and just pass a variable to assert, it does get interpolated without templating:

#\> cat c.yml

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [March 14, 2024, 2:26pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/5 "2024-03-14T14:26:56Z")

</div>

You were previously making use of double interpolation, where the first rendered `item` into the literal string `varA` and then dereferencing the literal string `varA` into its value. When you do `- item is defined` now, it is of course defined, and defined as the literal string value of the loop item, because you only provided a name of a variable and didn’t dereference it into its value.

Probably the easiest solution is to look into hostvars, using `item` as just the name of the var:

- assert:  
that:
- hostvars[inventory\_hostname][item] is defined  
loop:
- varA
- varB

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [March 14, 2024, 2:30pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/6 "2024-03-14T14:30:16Z")

</div>

In the first loop assert is evaluating that ‘item’ itself is defined.

In the second loop assert is evaluating whether a variable who’s name is stored in ‘item’ is defined.

> **% cat foo.yml**
> 
> * * *
> 
> - hosts: localhost
> 
> gather\_facts: no
> 
> become: no
> 
> tasks:
> 
> - name: without templating
> 
> assert:
> 
> that: “{{ item }} is defined”
> 
> loop:
> 
> - varA
> 
> - varB
> 
> **% ansible-playbook -i localhost, foo.yml -e varB=string**
> 
> PLAY [localhost] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
> 
> TASK [without templating] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
> 
> failed: [localhost] (item=varA) =\> {
> 
> “ansible\_loop\_var”: “item”,
> 
> “assertion”: “varA is defined”,
> 
> “changed”: false,
> 
> “evaluated\_to”: false,
> 
> “item”: “varA”,
> 
> “msg”: “Assertion failed”
> 
> }
> 
> ok: [localhost] =\> (item=varB) =\> {
> 
> “ansible\_loop\_var”: “item”,
> 
> “changed”: false,
> 
> “item”: “varB”,
> 
> “msg”: “All assertions passed”
> 
> }
> 
> PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
> 
> localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

NOTE that on the command line I explicitly define varB but not varA.

Walter

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [March 14, 2024, 2:43pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/7 "2024-03-14T14:43:58Z")

</div>

Thanks Matt. That makes sense. And furthermore, thanks for the pointer to use hostvars. It’s actually required, since as soon as I switch back to templating, I get “Conditional is marked as unsafe.”

Appreciate the help, everyone!

Rob

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [March 15, 2024, 7:02pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/8 "2024-03-15T19:02:27Z")

</div>

You can also use the vars lookup: lookup('vars', item), which has  
broader scope over hostvars.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [March 15, 2024, 7:03pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/9 "2024-03-15T19:03:14Z")

</div>

also varnames lookup

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [March 16, 2024, 1:05pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/10 "2024-03-16T13:05:27Z")

</div>

Hey Brian - any concerns with

assert:

that: item in vars

Short and sweet!

Rob

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/ansible/original/1X/1882d9a01da5d8996a862359b0913cc568a39b84.svg) [@system](https://forum.ansible.com/u/system)\
**Post date:** [March 18, 2024, 2:35pm UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/11 "2024-03-18T14:35:39Z")

</div>

`vars` was undocumented and for internal use, we stopped using it  
internally but have been unable to remove it (and save many resources)  
because people keep using(abusing) it.

Soon we will have 'variable deprecation' which will allow us to start  
removing things like these, `vars` has long been the first target for  
removal.

---

<div class="post-metadata">

**Author:** ![rjwagner.dba](https://avatars.discourse-cdn.com/v4/letter/r/e8c25b/32.png) [@rjwagner.dba](https://forum.ansible.com/u/rjwagner.dba)\
**Post date:** [March 19, 2024, 11:05am UTC](https://forum.ansible.com/t/interpolation-of-loop-variables/38715/12 "2024-03-19T11:05:23Z")

</div>

Got it, I’ll use the lookup. Thanks Brian
