nodejs/node · error · TemplateSyntaxError
unexpected '%s'
Error message
unexpected '%s'
What it means
The lexer maintains a balancing_stack of expected closers as it sees { ( [. When it encounters }, ), or ] and the stack is empty, there is no matching opener — an unbalanced closing bracket — and it raises TemplateSyntaxError('unexpected \'%s\'').
Source
Thrown at tools/inspector_protocol/jinja2/lexer.py:681
data = m.group(idx + 1)
if data or token not in ignore_if_empty:
yield lineno, token, data
lineno += data.count('\n')
# strings as token just are yielded as it.
else:
data = m.group()
# update brace/parentheses balance
if tokens == 'operator':
if data == '{':
balancing_stack.append('}')
elif data == '(':
balancing_stack.append(')')
elif data == '[':
balancing_stack.append(']')
elif data in ('}', ')', ']'):
if not balancing_stack:
raise TemplateSyntaxError('unexpected \'%s\'' %
data, lineno, name,
filename)
expected_op = balancing_stack.pop()
if expected_op != data:
raise TemplateSyntaxError('unexpected \'%s\', '
'expected \'%s\'' %
(data, expected_op),
lineno, name,
filename)
# yield items
if data or tokens not in ignore_if_empty:
yield lineno, tokens, data
lineno += data.count('\n')
# fetch new position into new variable so that we can check
# if there is a internal parsing error which would result
# in an infinite loop
pos2 = m.end()View on GitHub (pinned to 1b2de5e052)
Solutions
- Find the stray closing bracket at the reported line and remove it or add its matching opener.
- Balance every ( [ { with its ) ] } in expressions and macros calls.
Example fix
{# before #}
{{ format_name(user)) }}
{# after #}
{{ format_name(user) }} Defensive patterns
Strategy: validation
Validate before calling
def brackets_balanced(expr: str) -> bool:
pairs = {')': '(', ']': '[', '}': '{'}
stack = []
for ch in expr:
if ch in '([{':
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack Try / catch
from jinja2.exceptions import TemplateSyntaxError
try:
env.parse(source)
except TemplateSyntaxError as e:
log.error('unbalanced bracket at %s:%s', name, e.lineno) Prevention
- Pair-edit brackets: add the closer as soon as you open.
- Use env.parse to validate expressions before rendering.
- Use an editor that auto-pairs brackets.
When it happens
Trigger: A stray ), ], or } inside a Jinja2 expression/tag, e.g. {{ foo) }}, {% if (a and b) } %}, or an extra closing bracket from editing.
Common situations: Deleting an opening bracket while leaving its closer; copy-paste that introduces an unmatched closer; converting function-call syntax.
Related errors
- Invalid character in identifier
- unexpected '%s', expected '%s'
- unexpected char %r at %d
- chunk after expression
- unexpected end of template, expected %r.
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/224c1510bc7943e8.
Report an issue: GitHub.