antlr/antlr4 · error · ArgumentException

at index isn't a valid rule name

Error message

${word} at index ${startIndex} isn't a valid rule name

What it means

A word starting with a lowercase character is lexed as a RuleRef. The runtime asks the supplied Parser for its rule index; -1 means no rule with that name exists. The word is therefore a syntactically valid rule reference but is not defined by the target grammar.

Solutions

  1. Check parser.RuleNames and use the exact rule name from the generated parser.
  2. If the name is a token, make its first character uppercase so it is treated as a TokenRef.
  3. Regenerate the parser and lexer from the current grammar.
  4. Verify parser.GetRuleIndex(word) is not -1 before constructing XPath.

Example fix

// before
var xpath = new Antlr4.Runtime.Tree.Xpath.XPath(parser, "/expression");

// after
var xpath = new Antlr4.Runtime.Tree.Xpath.XPath(parser, "/expr"); // exact generated rule name
Defensive patterns

Strategy: validation

Validate before calling

static bool IsKnownRuleName(Parser parser, string word) {
    return char.IsLower(word[0]) && parser.GetRuleIndex(word) != -1;
}

Try / catch

try { var p = new Antlr4.Runtime.Tree.Xpath.XPath(parser, xpath); }
catch (ArgumentException ex) when (ex.Message.EndsWith("isn't a valid rule name")) { /* report unknown rule and check parser.RuleNames */ }

Prevention

When it happens

Trigger: Calling XPath with "/expr" when the grammar has no expr rule; using a renamed or removed rule; passing a parser generated from different grammar sources; or lowercasing a token name so it is interpreted as a rule.

Common situations: Grammar refactoring changes rule names; stale generated parser files; examples copied from another grammar; or uncertainty about whether a vocabulary name is a token or a rule.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/406d065025fc7e0a. Report an issue: GitHub.

Appendix: source

Thrown at runtime/CSharp/src/Tree/Xpath/XPath.cs:230

                {
                    return anywhere ? new XPathWildcardAnywhereElement() : (XPathElement)new XPathWildcardElement();
                }

                case XPathLexer.TokenRef:
                case XPathLexer.String:
                {
                    if (ttype == TokenConstants.InvalidType)
                    {
                        throw new ArgumentException(word + " at index " + wordToken.StartIndex + " isn't a valid token name");
                    }
                    return anywhere ? new XPathTokenAnywhereElement(word, ttype) : (XPathElement)new XPathTokenElement(word, ttype);
                }

                default:
                {
                    if (ruleIndex == -1)
                    {
                        throw new ArgumentException(word + " at index " + wordToken.StartIndex + " isn't a valid rule name");
                    }
                    return anywhere ? new XPathRuleAnywhereElement(word, ruleIndex) : (XPathElement)new XPathRuleElement(word, ruleIndex);
                }
            }
        }

        public static ICollection<IParseTree> FindAll(IParseTree tree, string xpath, Parser parser)
        {
            Antlr4.Runtime.Tree.Xpath.XPath p = new Antlr4.Runtime.Tree.Xpath.XPath(parser, xpath);
            return p.Evaluate(tree);
        }

        /// <summary>
        /// Return a list of all nodes starting at
        /// <paramref name="t"/>
        /// as root that satisfy the
        /// path. The root
        /// <c>/</c>

View on GitHub (pinned to 7d5770395b)