# Why does this if block + expression result in an undefined variable error?

**URL:** <https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091>\
**Category:** Ansible Project\
**Created:** [April 10, 2019, 2:56pm UTC](https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091 "2019-04-10T14:56:38Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alex\_Willmer](https://avatars.discourse-cdn.com/v4/letter/a/97f17d/32.png) [@Alex\_Willmer](https://forum.ansible.com/u/Alex_Willmer)\
**Post date:** [April 10, 2019, 2:56pm UTC](https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091/1 "2019-04-10T14:56:38Z")

</div>

I’ve been trying to understand why I’m getting an undefined variable error, even though the expression in question is surrounded by an if block that evaluates false. This only happens when the if block uses a host group.

I’ve reduced it to the following test case

$ cat inventory.yml  
group1:

group2:  
hosts:  
localhost:  
vars:

foo: “{{ groups.group1[0] }}”

Expected:  
$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if false %}{{ foo }}{% endif %}”  
localhost | SUCCESS =\> {  
“msg”: “”  
}  
$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if groups.group1 %}}{{ foo }}{% endif %}”  
localhost | SUCCESS =\> {  
“msg”: “”  
}

Actual:

$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if false %}{{ foo }}{% endif %}”  
localhost | SUCCESS =\> {  
“msg”: “”  
}  
$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if groups.group1 %}}{{ foo }}{% endif %}”  
localhost | FAILED! =\> {  
“msg”: “The task includes an option with an undefined variable. The error was: list object has no element 0”  
}

The foo variable is being referenced, even though it is inside an if block that evaluates false. This only occurs when I use groups.group1 in the if expression, AND I refer to the variable foo. Why is this?

$ ansible --version  
ansible 2.7.9  
config file = /etc/ansible/ansible.cfg  
configured module search path = [u’/home/willmerae/.ansible/plugins/modules’, u’/usr/share/ansible/plugins/modules’]  
ansible python module location = /usr/lib/python2.7/dist-packages/ansible  
executable location = /usr/bin/ansible  
python version = 2.7.12 (default, Nov 12 2018, 14:36:49) [GCC 5.4.0 20160609]  
$ ls -a  
. … inventory.yml

---

<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:** [April 18, 2019, 4:34pm UTC](https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091/2 "2019-04-18T16:34:12Z")

</div>

lazy evaluation prevents the error until the variable is actualy  
consumed, group1 is empty so [0] is pointing to 'the first host of a  
list w/o hosts', so the error is correct, you just avoid it in the  
first case because of the conditional.

---

<div class="post-metadata">

**Author:** ![Alex\_Willmer](https://avatars.discourse-cdn.com/v4/letter/a/97f17d/32.png) [@Alex\_Willmer](https://forum.ansible.com/u/Alex_Willmer)\
**Post date:** [April 23, 2019, 2:29pm UTC](https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091/3 "2019-04-23T14:29:40Z")

</div>

> lazy evaluation prevents the error until the variable is actualy  
> consumed, group1 is empty so [0] is pointing to ‘the first host of a  
> list w/o hosts’, so the error is correct,

I agree, and don’t contest this part. If foo is evaluated it should raise an error.

> you just avoid it in the first case because of the conditional.

T his part confuses me. I both cases the if condition evaluates false. So why is foo evaluated in one case but not the other?

Further info: I believe the behaviour I’m seeing is dependent on the version of Jinja2. If Jinja2 2.8 is installed then the “{% if false %}” case prints “”, and the “{% if groups.group1 %}” case raises the error. If Jinja2 2.9 or Jinja2 2.10 is installed then both cases raise the Error. This is based on testing across Ansible 2.7.{0,5,6,7,8,9,10} using Tox.

With thanks, Alex

---

<div class="post-metadata">

**Author:** ![Karl\_Auer](https://avatars.discourse-cdn.com/v4/letter/k/cc9497/32.png) [@Karl\_Auer](https://forum.ansible.com/u/Karl_Auer)\
**Post date:** [April 23, 2019, 3:20pm UTC](https://forum.ansible.com/t/why-does-this-if-block-expression-result-in-an-undefined-variable-error/30091/4 "2019-04-23T15:20:03Z")

</div>

Not sure if the following explanation will help.

Most languages will not continue evaluation of all the components in a boolean expression once enough have been evaluated to determine the answer.

It’s obvious that in “if A and B then C”, C will only get evaluated if both A and B are true. But most languages will not bother evaluating B if A is false, because if A is false, then “A and B” must be false too; there is no point evaluating B, because it can’t alter the overall value of “A and B”. In such languages, B will only get evaluated if A is _true_, because only then might evaluating B change the value of the overall expression.

Similarly, in “if A or B then C” there is no point evaluating B if A is true, because if A is true, “A or B” is true too. It doesn’t matter whether B is true or false. However in this situation, B will only get evaluated if A is _false_, because only in that case might evaluating B change the value of the overall expression.

I.e., the order of the subexpressions in a boolean expression can be important. Sometimes it is useful. A very common idiom in lots of languages is “test and use” - if the test fails, the use never happens.

Regards, K.
