nodejs/node · error · TemplateSyntaxError
unexpected '%s', expected '%s'
Error message
unexpected '%s', expected '%s'
What it means
Sibling of 612: a closing bracket }, ), or ] was found and the stack was non-empty, but the expected opener (top of balancing_stack) did not match — e.g. opened with '[' but closed with ')'. The lexer reports both the actual and the expected bracket.
Source
Thrown at tools/inspector_protocol/jinja2/lexer.py:686
# 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()
# handle state changes
if new_state is not None:
# remove the uppermost state
if new_state == '#pop':View on GitHub (pinned to 1b2de5e052)
Solutions
- Read both symbols in the message: it tells you which closer was found and which was expected.
- Replace the wrong closer with the matching one for the innermost opener.
Example fix
{# before #}
{{ items[0) }}
{# after #}
{{ items[0] }} Defensive patterns
Strategy: validation
Validate before calling
def brackets_match(expr: str) -> bool:
pairs = {')': '(', ']': '[', '}': '{'}
stack = []
for ch in expr:
if ch in '([{':
stack.append(ch)
elif ch in pairs:
if not stack:
return False
if 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('mismatched bracket at %s:%s: %s', name, e.lineno, e.message) Prevention
- Match each closer to the innermost opener of the same kind.
- Validate templates with env.parse in CI.
- Avoid nesting different bracket types densely; refactor long expressions.
When it happens
Trigger: Mismatched bracket pairs such as {{ foo[bar) }}, {{ func(x] }}, or {{ dict('k': v) }} confusing ( with [.
Common situations: Mixing parentheses, brackets, and braces when nesting calls/subscripts/literals; refactor typos.
Related errors
- Invalid character in identifier
- unexpected '%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/59a7ac5a6b193323.
Report an issue: GitHub.