nodejs/node · error · TemplateSyntaxError
Invalid character in identifier
Error message
Invalid character in identifier
What it means
During tokenization, when a 'name' token is produced Jinja2 validates it with str.isidentifier() (only when check_ident is active). If the characters do not form a legal Python identifier, the lexer raises TemplateSyntaxError('Invalid character in identifier'). This catches malformed variable/attribute names early.
Source
Thrown at tools/inspector_protocol/jinja2/lexer.py:579
"""
for lineno, token, value in stream:
if token in ignored_tokens:
continue
elif token == 'linestatement_begin':
token = 'block_begin'
elif token == 'linestatement_end':
token = 'block_end'
# we are not interested in those tokens in the parser
elif token in ('raw_begin', 'raw_end'):
continue
elif token == 'data':
value = self._normalize_newlines(value)
elif token == 'keyword':
token = value
elif token == 'name':
value = str(value)
if check_ident and not value.isidentifier():
raise TemplateSyntaxError(
'Invalid character in identifier',
lineno, name, filename)
elif token == 'string':
# try to unescape string
try:
value = self._normalize_newlines(value[1:-1]) \
.encode('ascii', 'backslashreplace') \
.decode('unicode-escape')
except Exception as e:
msg = str(e).split(':')[-1].strip()
raise TemplateSyntaxError(msg, lineno, name, filename)
elif token == 'integer':
value = int(value)
elif token == 'float':
value = float(value)
elif token == 'operator':
token = operators[value]
yield Token(lineno, token, value)View on GitHub (pinned to 1b2de5e052)
Solutions
- Rename variables to use only letters, digits, and underscores, and not start with a digit.
- Quote attribute names that contain special characters and access them via |attr("name") or subscript.
- Replace hyphens with underscores in context variable names.
Example fix
{# before #}
{{ user.first-name }}
{# after #}
{{ user.first_name }}
{# or for hyphenated keys: #}
{{ user['first-name'] }} Defensive patterns
Strategy: validation
Validate before calling
def is_valid_identifier(name: str) -> bool:
return isinstance(name, str) and name.isidentifier() Type guard
def valid_identifier(name) -> bool:
return isinstance(name, str) and name.isidentifier() Try / catch
from jinja2.exceptions import TemplateSyntaxError
try:
env.parse(source)
except TemplateSyntaxError as e:
if 'Invalid character in identifier' in str(e):
log.error('rename context vars to valid Python identifiers (line %s)', e.lineno)
raise Prevention
- Restrict context variable names to Python identifiers (letters, digits, underscore; no leading digit).
- Replace hyphens from external sources with underscores before passing to the template.
- Use dict-style access for keys that contain special characters.
When it happens
Trigger: A variable or attribute name containing illegal characters (e.g. {{ foo-bar }}, {{ 2cool }}, {{ user.name! }}), where the lexer classified the chunk as a name but it isn't a valid identifier.
Common situations: Using hyphens in variable names (common from CSS/HTML conventions); names starting with a digit; stray punctuation glued to an identifier.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unexpected '%s'
- 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/0a3fe50e61f54cc0.
Report an issue: GitHub.