Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Ansible By James Joyner IV · · 9 min read

Ansible Error Guide: 'template error while templating string' Jinja2 Failure

Fix Ansible's 'template error while templating string' Jinja2 error: diagnose syntax mistakes, undefined filters, type errors, and bad expressions inside templates and vars.

  • #ansible
  • #troubleshooting
  • #errors
  • #jinja2

Exact Error Message

fatal: [app-01]: FAILED! => {
    "changed": false,
    "msg": "AnsibleError: template error while templating string: expected token 'end of print statement', got '='. String: {{ user_count = 5 }}"
}

The headline is always template error while templating string:, followed by the specific Jinja2 complaint and the offending string. Common tails include expected token ..., unexpected '}', No filter named '...', and expected name or number.

What the Error Means

Ansible evaluates Jinja2 expressions (anything inside {{ ... }} or {% ... %}) when it renders templates, conditionals, and variable values. When the Jinja2 engine cannot parse or evaluate one of those expressions, it raises a templating error and Ansible surfaces it as template error while templating string.

This is a parse/evaluation failure inside the expression itself — different from AnsibleUndefinedVariable, which means a variable was referenced but never defined. Here the engine got far enough to try to compile your expression and choked on its syntax or an operation it could not perform.

Common Causes

  • Using = for assignment inside {{ }} instead of comparison ==, e.g. {{ x = 5 }}.
  • A typo’d or non-existent filter, e.g. {{ value | defaul('x') }} or a filter from a collection that is not installed.
  • Mismatched or doubled braces: {{{ var }}} or a missing closing }}.
  • Calling a string method or filter on the wrong type (passing a list where a string is expected).
  • Nesting {{ }} inside {{ }} (you almost never need the inner braces).
  • A raw Jinja2 control character ({, }, %) in a .j2 template that was meant as literal text.

How to Reproduce the Error

Create a template with an invalid expression and apply it:

# templates/app.conf.j2
max_users = {{ user_count = 5 }}
ansible-playbook deploy.yml -i inventory.ini --check --diff -vvv
fatal: [app-01]: FAILED! => {"changed": false, "msg": "AnsibleError: template error while templating string: expected token 'end of print statement', got '='. String: max_users = {{ user_count = 5 }}"}

A missing-filter variant looks like this:

fatal: [app-01]: FAILED! => {"msg": "template error while templating string: No filter named 'defaul'. String: {{ region | defaul('us-east-1') }}"}

Diagnostic Commands

Run the play in check mode with full verbosity to capture the failing string verbatim:

ansible-playbook deploy.yml -i inventory.ini --check --diff -vvv

Render a suspect template in isolation against a real host’s facts using the template lookup in a debug task, or test an expression directly:

ansible app-01 -i inventory.ini -m debug -a "msg={{ region | default('us-east-1') }}"

Confirm whether a filter comes from a collection that is installed:

ansible-doc -t filter -l | grep -i community

Inspect the variables feeding the template so you know their real types:

ansible app-01 -i inventory.ini -m setup -a "filter=ansible_default_ipv4"

Step-by-Step Resolution

  1. Read the String: portion of the error. Ansible prints the exact expression that failed — start there rather than guessing which line.

  2. Fix the operator. Inside {{ }} you compare, you do not assign. Replace = with == for comparison, or move the assignment into set_fact / vars:

- set_fact:
    user_count: 5
  1. Correct filter names. defaul should be default, to_json not tojson in some contexts. Verify with ansible-doc -t filter <name>.

  2. Balance the braces. Use exactly {{ expr }} for output and {% stmt %} for logic. Remove any stray inner {{ }}.

  3. Match types. If a filter expects a string but receives a list, convert it first ({{ items | join(',') }}), or guard with default:

{{ (region | default('us-east-1')) }}
  1. Escape literal Jinja2 in templates. If a .j2 file must contain literal {{ or %, wrap it:
{% raw %}{{ this stays literal }}{% endraw %}
  1. Re-run in check mode and confirm the template renders cleanly before applying for real:
ansible-playbook deploy.yml -i inventory.ini --check --diff

Prevention and Best Practices

  • Keep expressions simple. Push complex logic into set_fact or precomputed variables rather than cramming it into one template line.
  • Always guard optional variables with | default(...) so a missing value degrades gracefully instead of erroring.
  • Lint templates. ansible-lint catches many bad expressions before runtime.
  • Test templates against real facts in check mode in CI, not just on your laptop where variables happen to be defined.
  • Pin and install the collections that provide your filters; a No filter named error often just means community.general is missing.
  • Use {% raw %} blocks for config files that legitimately contain {{ (for example, other templating engines’ syntax).
  • AnsibleUndefinedVariable: '...' is undefined — the variable does not exist, as opposed to a syntax error in the expression.
  • The conditional check '...' failed — a when: expression that templated but evaluated to an error.
  • No filter named '...' — a specific sub-case usually caused by a missing collection.
  • Unexpected templating type error — a type mismatch (for example, applying a string filter to a dict).

Frequently Asked Questions

What is the difference between this and AnsibleUndefinedVariable? This error is a parse/evaluation failure in the expression itself. AnsibleUndefinedVariable means the syntax was fine but a referenced variable has no value.

Why does {{ x = 5 }} fail? Jinja2 print statements ({{ }}) only output expressions; they cannot assign. Use set_fact or vars, and use == for comparison.

My filter exists in docs but Ansible says No filter named. The filter likely lives in a collection (e.g. community.general) that is not installed. Install it with ansible-galaxy collection install and verify with ansible-doc -t filter.

How do I keep literal braces in a template? Wrap the section in {% raw %} ... {% endraw %} so Jinja2 emits it verbatim. For more Jinja2 and variable patterns, see the Ansible guides.

Free download · 368-page PDF

Download the Free 500-Prompt DevOps AI Toolkit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.