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.