{"record":{"id":"3c6dcf464e024fa5","repo":"antlr/antlr4","slug":"s-at-index-d-isn-t-a-valid-rule-name","errorCode":null,"errorMessage":"%s at index %d isn't a valid rule name","messagePattern":"(.+?) at index (.+?) isn't a valid rule name","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"runtime/Python3/src/antlr4/xpath/XPath.py","lineNumber":160,"sourceCode":"            tsource = self.parser.getTokenStream().tokenSource\n\n            ttype = Token.INVALID_TYPE\n            if wordToken.type == XPathLexer.TOKEN_REF:\n                if word in tsource.ruleNames:\n                    ttype = tsource.ruleNames.index(word) + 1\n            else:\n                if word in tsource.literalNames:\n                    ttype = tsource.literalNames.index(word)\n\n            if ttype == Token.INVALID_TYPE:\n                raise Exception(\"%s at index %d isn't a valid token name\" % (word, wordToken.tokenIndex))\n            return XPathTokenAnywhereElement(word, ttype) if anywhere else XPathTokenElement(word, ttype)\n\n        else:\n            ruleIndex = self.parser.ruleNames.index(word) if word in self.parser.ruleNames else -1\n\n            if ruleIndex == -1:\n                raise Exception(\"%s at index %d isn't a valid rule name\" % (word, wordToken.tokenIndex))\n            return XPathRuleAnywhereElement(word, ruleIndex) if anywhere else XPathRuleElement(word, ruleIndex)\n\n\n    @staticmethod\n    def findAll(tree:ParseTree, xpath:str, parser:Parser):\n        p = XPath(parser, xpath)\n        return p.evaluate(tree)\n\n    #\n    # Return a list of all nodes starting at {@code t} as root that satisfy the\n    # path. The root {@code /} is relative to the node passed to\n    # {@link #evaluate}.\n    #\n    def evaluate(self, t:ParseTree):\n        dummyRoot = ParserRuleContext()\n        dummyRoot.children = [t] # don't set t's parent.\n\n        work = [dummyRoot]","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Python3/src/antlr4/xpath/XPath.py#L142-L178","documentation":"Raised by XPath.getXPathElement() in the Python3 runtime when a RULE_REF in the path does not name any parser rule. The evaluator needs the rule index to match rule-invocation nodes; parser.ruleNames.index() returns -1 for unknown names.","triggerScenarios":"XPath with a path like '/expr' when the parser has no rule named expr (e.g. it was renamed to expression), or using a lexer rule name in rule position.","commonSituations":"Grammar refactors, copy/pasting XPath examples from another grammar, or confusion between lexer and parser rule namespaces.","solutions":["Match the rule name exactly to an entry in parser.ruleNames","If the name is a token/lexer rule, reference it as a token instead","Update XPath strings after every grammar rename and regenerate"],"exampleFix":"# before: rule is 'expression' in this grammar\nnodes = XPath.findAll(tree, \"/expr\", parser)\n\n# after\nnodes = XPath.findAll(tree, \"/expression\", parser)","handlingStrategy":"validation","validationCode":"if rule_name not in parser.ruleNames:\n    raise ValueError(f'{rule_name} is not a parser rule name')","typeGuard":"def is_known_rule_name(name: str, parser) -> bool:\n    return name in parser.ruleNames","tryCatchPattern":"try:\n    nodes = XPath.findAll(tree, xpath, parser)\nexcept Exception as e:\n    if \"isn't a valid rule name\" in str(e):\n        # find the correct rule name in parser.ruleNames\n        ...","preventionTips":["Cross-check rule names with parser.ruleNames","Regenerate code and XPath queries together after grammar edits"],"tags":["antlr","python","xpath","validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}