Fix Ansible Template Errors — Jinja2 Syntax Guide
Error 1: Unexpected Token
AnsibleError: template error while templating string:
unexpected '}'
# WRONG — nested braces need spaces
msg: "{{ dict['key'] }}" # Usually fine
msg: "{{dict['key']}}" # ← Missing spaces can cause issues
# WRONG — Jinja2 inside Jinja2
msg: "{{ '{{ not_a_variable }}' }}"
# RIGHT — use raw block
msg: "{% raw %}{{ not_a_variable }}{% endraw %}"
Error 2: Filter Not Found
TemplateAssertionError: No filter named 'to_datetime'
# Check if the filter requires a collection
ansible-doc -t filter -l | grep datetime
# Install required collection
ansible-galaxy collection install community.general
Error 3: Template File Not Found
AnsibleFileNotFound: Could not find or access 'templates/nginx.conf.j2'
# Expected directory structure
roles/
webserver/
templates/ ← Ansible looks here automatically
nginx.conf.j2
tasks/
main.yml
# In tasks/main.yml — just use the filename
- ansible.builtin.template:
src: nginx.conf.j2 # Not templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
Error 4: Whitespace Issues in Generated Files
# Config file has unwanted blank lines
{% for server in servers %}
server {{ server.name }} {{ server.ip }}
{% endfor %}
# Fix: use minus sign to strip whitespace
{% for server in servers -%}
server {{ server.name }} {{ server.ip }}
{% endfor -%}
Error 5: Type Errors in Filters
AnsibleFilterError: int() arg must be a string or number, not 'AnsibleUndefined'
# WRONG — variable might not exist
port: "{{ custom_port | int }}"
# RIGHT — default before converting
port: "{{ custom_port | default(8080) | int }}"
Useful Debugging Techniques
Preview Template Output
- name: Render template to variable
ansible.builtin.set_fact:
rendered: "{{ lookup('template', 'mytemplate.j2') }}"
- name: Show rendered output
debug:
var: rendered
Check Template Syntax
# Use Python to validate Jinja2 syntax
python3 -c "
from jinja2 import Environment
env = Environment()
env.parse(open('templates/test.j2').read())
print('Syntax OK')
"
Common Filters Cheat Sheet
# String
{{ name | upper }}
{{ name | lower }}
{{ name | capitalize }}
{{ name | replace('old', 'new') }}
{{ name | regex_replace('^prefix_', '') }}
# Lists
{{ list | join(', ') }}
{{ list | unique }}
{{ list | sort }}
{{ list | length }}
{{ list | first }}
{{ list | last }}
# Defaults
{{ var | default('fallback') }}
{{ var | default(omit) }}
{{ var | mandatory }}
# Type conversion
{{ value | int }}
{{ value | float }}
{{ value | bool }}
{{ value | string }}
# JSON/YAML
{{ dict | to_json }}
{{ dict | to_yaml }}
{{ json_string | from_json }}
Conclusion
Most template errors come from undefined variables (use | default()), missing filters (install collections), and whitespace control (use {%- and -%}). Preview output with lookup('template') for debugging.