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

  1. Rename variables to use only letters, digits, and underscores, and not start with a digit.
  2. Quote attribute names that contain special characters and access them via |attr("name") or subscript.
  3. 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

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

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/0a3fe50e61f54cc0. Report an issue: GitHub.