diff --git a/changelogs/fragments/jinja-syntax-error-line-numbers.yml b/changelogs/fragments/jinja-syntax-error-line-numbers.yml new file mode 100644 index 00000000000..6ffd2793c07 --- /dev/null +++ b/changelogs/fragments/jinja-syntax-error-line-numbers.yml @@ -0,0 +1,2 @@ +bugfixes: + - template module - Report the line number for Jinja syntax errors in template files. diff --git a/lib/ansible/_internal/_templating/_jinja_bits.py b/lib/ansible/_internal/_templating/_jinja_bits.py index 34e777bac2f..5f675b36fdd 100644 --- a/lib/ansible/_internal/_templating/_jinja_bits.py +++ b/lib/ansible/_internal/_templating/_jinja_bits.py @@ -496,6 +496,14 @@ def create_template_error(ex: Exception, variable: t.Any, is_expression: bool) - if isinstance(ex, RecursionError): msg = f"Recursive loop detected in {kind}." elif isinstance(ex, TemplateSyntaxError): + if (origin := Origin.get_tag(variable)) and origin.line_num is None and ex.lineno > 0: + # When there is an origin without a line number, use the line number provided by the Jinja syntax error. + # This should only occur on templates which represent the entire contents of a file. + # Templates loaded from within a file, such as YAML, will use the existing origin. + # It's not possible to combine origins here, due to potential layout differences between the original content and the parsed output. + # This can happen, for example, with YAML multi-line strings. + variable = origin.replace(line_num=ex.lineno, col_num=None).tag(variable) + msg = f"Syntax error in {kind}." if is_expression and is_possibly_template(variable): diff --git a/test/integration/targets/templating-syntax-errors/aliases b/test/integration/targets/templating-syntax-errors/aliases new file mode 100644 index 00000000000..9d96756443a --- /dev/null +++ b/test/integration/targets/templating-syntax-errors/aliases @@ -0,0 +1,2 @@ +context/controller +shippable/posix/group4 diff --git a/test/integration/targets/templating-syntax-errors/runme.sh b/test/integration/targets/templating-syntax-errors/runme.sh new file mode 100755 index 00000000000..9cd03f70636 --- /dev/null +++ b/test/integration/targets/templating-syntax-errors/runme.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -eux + +ansible-playbook template-file.yml "${@}" | tee template-file.out + +echo "Verifying contents of error reports ..." + +# verify the template-file error report is correct +grep 'template-file.j2:5' template-file.out +grep '5 {% sorry' template-file.out + +echo "PASS" diff --git a/test/integration/targets/templating-syntax-errors/template-file.j2 b/test/integration/targets/templating-syntax-errors/template-file.j2 new file mode 100644 index 00000000000..4fb95522629 --- /dev/null +++ b/test/integration/targets/templating-syntax-errors/template-file.j2 @@ -0,0 +1,5 @@ +line 1 +line 2 +line 3 +line 4 +{% sorry diff --git a/test/integration/targets/templating-syntax-errors/template-file.yml b/test/integration/targets/templating-syntax-errors/template-file.yml new file mode 100644 index 00000000000..abb14bf6591 --- /dev/null +++ b/test/integration/targets/templating-syntax-errors/template-file.yml @@ -0,0 +1,7 @@ +- hosts: localhost + gather_facts: no + tasks: + - template: + src: template-file.j2 + dest: template-file.txt + ignore_errors: yes