<h5 dir="auto">ISSUE TYPE</h5>
<ul dir="auto">
<li>Bug Report</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>
<ul dir="auto">
<li>template expansion</li>
</ul>
<h5 dir="auto">ANSIBLE VERSION</h5>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ansible 2.2.1.0
  config file =
  configured module search path = Default w/o overrides"><pre class="notranslate"><code class="notranslate">ansible 2.2.1.0
  config file =
  configured module search path = Default w/o overrides
</code></pre></div>
<h5 dir="auto">CONFIGURATION</h5>
<p dir="auto">N/A</p>
<h5 dir="auto">OS / ENVIRONMENT</h5>
<p dir="auto">Ubuntu 16.04. ansible installed via pip.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ pip list --format=legacy
ansible (2.2.1.0)
cffi (1.9.1)
configobj (5.0.6)
crit (0.0.1)
cryptography (1.7.1)
dynagen (0.9.0)
enum34 (1.1.6)
idna (2.2)
ipaddr (2.1.11)
ipaddress (1.0.18)
Jinja2 (2.9.4)
MarkupSafe (0.23)
paramiko (2.1.1)
pip (9.0.1)
protobuf (3.1.0.post1)
pyasn1 (0.1.9)
pycparser (2.17)
pycrypto (2.6.1)
python-apt (1.1.0b1)
PyYAML (3.12)
setuptools (33.1.1)
six (1.10.0)
wheel (0.29.0)"><pre class="notranslate"><code class="notranslate">$ pip list --format=legacy
ansible (2.2.1.0)
cffi (1.9.1)
configobj (5.0.6)
crit (0.0.1)
cryptography (1.7.1)
dynagen (0.9.0)
enum34 (1.1.6)
idna (2.2)
ipaddr (2.1.11)
ipaddress (1.0.18)
Jinja2 (2.9.4)
MarkupSafe (0.23)
paramiko (2.1.1)
pip (9.0.1)
protobuf (3.1.0.post1)
pyasn1 (0.1.9)
pycparser (2.17)
pycrypto (2.6.1)
python-apt (1.1.0b1)
PyYAML (3.12)
setuptools (33.1.1)
six (1.10.0)
wheel (0.29.0)
</code></pre></div>
<h5 dir="auto">SUMMARY</h5>
<p dir="auto">When one template <em>imports</em> another one, and then <em>includes</em> another template, it barfs with "KeyError: 'undefined variable: 0'"</p>
<h5 dir="auto">STEPS TO REPRODUCE</h5>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# test.yml
- hosts: localhost
  tasks:
    - template:
        src: foo
        dest: /tmp/foo

# templates/foo
{% import 'qux' as qux with context %}
hello world
{{ qux.wibble }}
{% include 'bar' %}

# templates/bar
Goodbye

# templates/qux
{% set wibble = &quot;WIBBLE&quot; %}"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> test.yml</span>
- <span class="pl-ent">hosts</span>: <span class="pl-s">localhost</span>
  <span class="pl-ent">tasks</span>:
    - <span class="pl-ent">template</span>:
        <span class="pl-ent">src</span>: <span class="pl-s">foo</span>
        <span class="pl-ent">dest</span>: <span class="pl-s">/tmp/foo</span>

<span class="pl-c"><span class="pl-c">#</span> templates/foo</span>
<span class="pl-s">{% import 'qux' as qux with context %}</span>
<span class="pl-s">hello world</span>
<span class="pl-s">{{ qux.wibble }}</span>
<span class="pl-s">{% include 'bar' %}</span>

<span class="pl-c"><span class="pl-c">#</span> templates/bar</span>
<span class="pl-s">Goodbye</span>

<span class="pl-c"><span class="pl-c">#</span> templates/qux</span>
<span class="pl-s">{% set wibble = "WIBBLE" %}</span></pre></div>
<h5 dir="auto">EXPECTED RESULTS</h5>
<p dir="auto">/tmp/foo to be created with:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="hello world
WIBBLE
Goodbye"><pre class="notranslate"><code class="notranslate">hello world
WIBBLE
Goodbye
</code></pre></div>
<h5 dir="auto">ACTUAL RESULTS</h5>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="TASK [template] ****************************************************************
task path: /home/ubuntu/bug/test.yml:3
fatal: [localhost]: FAILED! =&gt; {
    &quot;changed&quot;: false,
    &quot;failed&quot;: true,
    &quot;invocation&quot;: {
        &quot;module_args&quot;: {
            &quot;dest&quot;: &quot;/tmp/foo&quot;,
            &quot;src&quot;: &quot;foo&quot;
        },
        &quot;module_name&quot;: &quot;template&quot;
    },
    &quot;msg&quot;: &quot;KeyError: 'undefined variable: 0'&quot;
}"><pre class="notranslate"><code class="notranslate">TASK [template] ****************************************************************
task path: /home/ubuntu/bug/test.yml:3
fatal: [localhost]: FAILED! =&gt; {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "dest": "/tmp/foo",
            "src": "foo"
        },
        "module_name": "template"
    },
    "msg": "KeyError: 'undefined variable: 0'"
}
</code></pre></div>
<h5 dir="auto">ADDITIONAL INFO</h5>
<p dir="auto">If you change <code class="notranslate">templates/foo</code> to this, it works fine:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="hello world
{% include 'bar' %}"><pre class="notranslate"><code class="notranslate">hello world
{% include 'bar' %}
</code></pre></div>
<p dir="auto">And so does this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{% import 'qux' as qux with context %}
hello world
{{ qux.wibble }}"><pre class="notranslate"><code class="notranslate">{% import 'qux' as qux with context %}
hello world
{{ qux.wibble }}
</code></pre></div>
<p dir="auto">So it appears to be something to do with the <em>combination</em> of import and include which is causing it to barf.</p>
<p dir="auto">However if you remove the "with context", like this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{% import 'qux' as qux  %}
hello world
{{ qux.wibble }}"><pre class="notranslate"><code class="notranslate">{% import 'qux' as qux  %}
hello world
{{ qux.wibble }}
</code></pre></div>
<p dir="auto">then it barfs in a different way:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="TASK [template] ****************************************************************
task path: /home/ubuntu/bug/test.yml:3
fatal: [localhost]: FAILED! =&gt; {
    &quot;changed&quot;: false,
    &quot;failed&quot;: true,
    &quot;invocation&quot;: {
        &quot;module_args&quot;: {
            &quot;dest&quot;: &quot;/tmp/foo&quot;,
            &quot;src&quot;: &quot;foo&quot;
        },
        &quot;module_name&quot;: &quot;template&quot;
    },
    &quot;msg&quot;: &quot;AttributeError: 'NoneType' object has no attribute 'add_locals'&quot;
}"><pre class="notranslate"><code class="notranslate">TASK [template] ****************************************************************
task path: /home/ubuntu/bug/test.yml:3
fatal: [localhost]: FAILED! =&gt; {
    "changed": false,
    "failed": true,
    "invocation": {
        "module_args": {
            "dest": "/tmp/foo",
            "src": "foo"
        },
        "module_name": "template"
    },
    "msg": "AttributeError: 'NoneType' object has no attribute 'add_locals'"
}
</code></pre></div>
<p dir="auto">So there is a potentially separate issue, that 'import ... with context' works, but 'import' by itself does not, in Ansible.</p>
<p dir="auto">The <a href="http://jinja.pocoo.org/docs/2.9/templates/#import-context-behavior" rel="nofollow">difference</a> is that in the latter case, jinja2 will cache the import with the template (since it doesn't depend on any of the dynamic context in that particular expansion of the template)</p>
<p dir="auto">Finally: this appears not to be a bug with jinja2 itself. Using jinja2 API directly runs the test case with no problem:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#!/usr/bin/python
from jinja2 import Environment, FileSystemLoader
env = Environment(
    loader=FileSystemLoader('templates'),
)
template = env.get_template('foo')
print template.render()"><pre class="notranslate"><code class="notranslate">#!/usr/bin/python
from jinja2 import Environment, FileSystemLoader
env = Environment(
    loader=FileSystemLoader('templates'),
)
template = env.get_template('foo')
print template.render()
</code></pre></div>
<p dir="auto">gives:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="$ python test.py

hello world
WIBBLE
Goodbye"><pre class="notranslate"><code class="notranslate">$ python test.py

hello world
WIBBLE
Goodbye
</code></pre></div>
<h5 dir="auto">ISSUE TYPE</h5>
<ul dir="auto">
<li>Bug Report</li>
</ul>
<h5 dir="auto">COMPONENT NAME</h5>
<p dir="auto">Template</p>
<h5 dir="auto">ANSIBLE VERSION</h5>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="ansible 2.3.0 (devel 0aad46c85b) last updated 2017/01/09 16:11:21 (GMT -400)
  config file = /home/jadams/.ansible.cfg
  configured module search path = Default w/o overrides
"><pre class="notranslate"><code class="notranslate">ansible 2.3.0 (devel 0aad46c85b) last updated 2017/01/09 16:11:21 (GMT -400)
  config file = /home/jadams/.ansible.cfg
  configured module search path = Default w/o overrides

</code></pre></div>
<h5 dir="auto">CONFIGURATION</h5>
<p dir="auto">Tested on vanilla / no extra configuration</p>
<h5 dir="auto">OS / ENVIRONMENT</h5>
<p dir="auto">N/A but tested from Fedora 25</p>
<h5 dir="auto">SUMMARY</h5>
<p dir="auto">When Jinja2 dependency is &gt;= 2.9.0, nested templates inside of loops defined in a parent template do not receive the local scope. For example:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{% for item in foo %}
    {% include &quot;other_template.j2&quot; %}
{% endfor %"><pre class="notranslate"><code class="notranslate">{% for item in foo %}
    {% include "other_template.j2" %}
{% endfor %
</code></pre></div>
<p dir="auto">In the above example, other_template.j2 would not have the item variable defined.</p>
<h5 dir="auto">STEPS TO REPRODUCE</h5>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# Example Playbook
- hosts: localhost
  connection: local
  vars:
    foo:
      - bar
      - baz
  tasks:
    - name: Test Template
      template: src=parent.j2 dest=/tmp/template.out"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> Example Playbook</span>
- <span class="pl-ent">hosts</span>: <span class="pl-s">localhost</span>
  <span class="pl-ent">connection</span>: <span class="pl-s">local</span>
  <span class="pl-ent">vars</span>:
    <span class="pl-ent">foo</span>:
      - <span class="pl-s">bar</span>
      - <span class="pl-s">baz</span>
  <span class="pl-ent">tasks</span>:
    - <span class="pl-ent">name</span>: <span class="pl-s">Test Template</span>
      <span class="pl-ent">template</span>: <span class="pl-s">src=parent.j2 dest=/tmp/template.out</span></pre></div>
<div class="highlight highlight-text-html-django notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# parent.j2
{% for item in foo %}
    {% include &quot;subtemplate.j2&quot; %}
{% endfor %}
"><pre class="notranslate"># parent.j2
<span class="pl-e">{%</span> <span class="pl-k">for</span> <span class="pl-s">item</span> <span class="pl-k">in</span> <span class="pl-s">foo</span> <span class="pl-e">%}</span>
    <span class="pl-e">{%</span> <span class="pl-k">include</span> <span class="pl-s">"subtemplate.j2"</span> <span class="pl-e">%}</span>
<span class="pl-e">{%</span> <span class="pl-k">endfor</span> <span class="pl-e">%}</span>
</pre></div>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#subtemplate.j2
{{ item }}"><pre class="notranslate"><code class="notranslate">#subtemplate.j2
{{ item }}
</code></pre></div>
<h5 dir="auto">EXPECTED RESULTS</h5>
<p dir="auto">Expected the output of the following file:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="bar
baz"><pre class="notranslate"><code class="notranslate">bar
baz
</code></pre></div>
<h5 dir="auto">ACTUAL RESULTS</h5>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="TASK [Test Template] ************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! =&gt; {&quot;changed&quot;: false, &quot;failed&quot;: true, &quot;msg&quot;: &quot;AnsibleUndefinedVariable: 'item' is undefined&quot;}"><pre class="notranslate"><code class="notranslate">TASK [Test Template] ************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! =&gt; {"changed": false, "failed": true, "msg": "AnsibleUndefinedVariable: 'item' is undefined"}
</code></pre></div>
<p dir="auto">I believe this is because of the Jinja2 Context changes mentioned <a href="http://jinja.pocoo.org/docs/2.9/changelog/#version-2-9" rel="nofollow">here</a> in combination with Ansible overriding default Jinja2 functions. I wasn't able to track down the root cause in my limited testing.</p>