{"record":{"id":"0a3fe50e61f54cc0","repo":"nodejs/node","slug":"invalid-character-in-identifier","errorCode":null,"errorMessage":"Invalid character in identifier","messagePattern":"Invalid character in identifier","errorType":"exception","errorClass":"TemplateSyntaxError","httpStatus":null,"severity":"error","filePath":"tools/inspector_protocol/jinja2/lexer.py","lineNumber":579,"sourceCode":"        \"\"\"\n        for lineno, token, value in stream:\n            if token in ignored_tokens:\n                continue\n            elif token == 'linestatement_begin':\n                token = 'block_begin'\n            elif token == 'linestatement_end':\n                token = 'block_end'\n            # we are not interested in those tokens in the parser\n            elif token in ('raw_begin', 'raw_end'):\n                continue\n            elif token == 'data':\n                value = self._normalize_newlines(value)\n            elif token == 'keyword':\n                token = value\n            elif token == 'name':\n                value = str(value)\n                if check_ident and not value.isidentifier():\n                    raise TemplateSyntaxError(\n                        'Invalid character in identifier',\n                        lineno, name, filename)\n            elif token == 'string':\n                # try to unescape string\n                try:\n                    value = self._normalize_newlines(value[1:-1]) \\\n                        .encode('ascii', 'backslashreplace') \\\n                        .decode('unicode-escape')\n                except Exception as e:\n                    msg = str(e).split(':')[-1].strip()\n                    raise TemplateSyntaxError(msg, lineno, name, filename)\n            elif token == 'integer':\n                value = int(value)\n            elif token == 'float':\n                value = float(value)\n            elif token == 'operator':\n                token = operators[value]\n            yield Token(lineno, token, value)","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/inspector_protocol/jinja2/lexer.py#L561-L597","documentation":"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.","triggerScenarios":"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.","commonSituations":"Using hyphens in variable names (common from CSS/HTML conventions); names starting with a digit; stray punctuation glued to an identifier.","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."],"exampleFix":"{# before #}\n{{ user.first-name }}\n\n{# after #}\n{{ user.first_name }}\n{# or for hyphenated keys: #}\n{{ user['first-name'] }}","handlingStrategy":"validation","validationCode":"def is_valid_identifier(name: str) -> bool:\n    return isinstance(name, str) and name.isidentifier()","typeGuard":"def valid_identifier(name) -> bool:\n    return isinstance(name, str) and name.isidentifier()","tryCatchPattern":"from jinja2.exceptions import TemplateSyntaxError\ntry:\n    env.parse(source)\nexcept TemplateSyntaxError as e:\n    if 'Invalid character in identifier' in str(e):\n        log.error('rename context vars to valid Python identifiers (line %s)', e.lineno)\n    raise","preventionTips":["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."],"tags":["jinja2","syntax","lexer","identifier"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}