{"record":{"id":"31abaf428a7a8b12","repo":"antlr/antlr4","slug":"unknown-rule-tag-in-pattern-pattern","errorCode":null,"errorMessage":"Unknown rule {tag} in pattern: {pattern}","messagePattern":"Unknown rule (.+?) in pattern: (.+?)","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs","lineNumber":552,"sourceCode":"                    // add special rule token or conjure up new token from name\n                    if (System.Char.IsUpper(tagChunk.Tag[0]))\n                    {\n                        int ttype = parser.GetTokenType(tagChunk.Tag);\n                        if (ttype == TokenConstants.InvalidType)\n                        {\n                            throw new ArgumentException(\"Unknown token \" + tagChunk.Tag + \" in pattern: \" + pattern);\n                        }\n                        TokenTagToken t = new TokenTagToken(tagChunk.Tag, ttype, tagChunk.Label);\n                        tokens.Add(t);\n                    }\n                    else\n                    {\n                        if (System.Char.IsLower(tagChunk.Tag[0]))\n                        {\n                            int ruleIndex = parser.GetRuleIndex(tagChunk.Tag);\n                            if (ruleIndex == -1)\n                            {\n                                throw new ArgumentException(\"Unknown rule \" + tagChunk.Tag + \" in pattern: \" + pattern);\n                            }\n                            int ruleImaginaryTokenType = parser.GetATNWithBypassAlts().ruleToTokenType[ruleIndex];\n                            tokens.Add(new RuleTagToken(tagChunk.Tag, ruleImaginaryTokenType, tagChunk.Label));\n                        }\n                        else\n                        {\n                            throw new ArgumentException(\"invalid tag: \" + tagChunk.Tag + \" in pattern: \" + pattern);\n                        }\n                    }\n                }\n                else\n                {\n                    TextChunk textChunk = (TextChunk)chunk;\n                    AntlrInputStream @in = new AntlrInputStream(textChunk.Text);\n                    lexer.SetInputStream(@in);\n                    IToken t = lexer.NextToken();\n                    while (t.Type != TokenConstants.EOF)\n                    {","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/CSharp/src/Tree/Pattern/ParseTreePatternMatcher.cs#L534-L570","documentation":"While compiling a pattern, a tag starting with a lowercase letter (rule tag, e.g. <expr>) does not resolve to any rule index in the parser (GetRuleIndex returned -1). Rule tags must name a parser rule declared in the grammar the parser was generated from; unknown names indicate a typo or a grammar/parser version mismatch.","triggerScenarios":"CompileParseTreePattern(\"<ID> = <expression>\", ...) when the rule is called expr; using a pattern authored for a different grammar; rule renamed during refactoring without regenerating or updating patterns.","commonSituations":"Patterns stored as string constants drift after grammar refactors; multi-version tooling where the same pattern is run against parsers from several grammar versions; documentation examples copied into a project with different rule names.","solutions":["Rename the tag to the exact rule name from the grammar (check parser.RuleNames or the generated parser class).","If the tag names a token, capitalize its first letter so it is treated as a token tag.","Regenerate the parser after grammar edits and update pattern strings together; add a startup check that compiles all patterns to fail fast.","Wrap CompileParseTreePattern in try/catch ArgumentException to log which pattern failed when patterns come from external config."],"exampleFix":"// before\nvar p = parser.CompileParseTreePattern(\"<ID> = <expression>\", ExprParser.RULE_assign, null);\n\n// after (rule is 'expr' in the grammar)\nvar p = parser.CompileParseTreePattern(\"<ID> = <expr>\", ExprParser.RULE_assign, null);","handlingStrategy":"validation","validationCode":"foreach (var tag in ExtractRuleTags(pattern))\n    if (parser.GetRuleIndex(tag) == -1)\n        throw new ArgumentException($\"pattern references unknown rule <{tag}>\");\nvar p = parser.CompileParseTreePattern(pattern, ruleIndex, null);","typeGuard":null,"tryCatchPattern":"try { var p = parser.CompileParseTreePattern(pattern, ruleIndex, null); } catch (ArgumentException ex) when (ex.Message.StartsWith(\"Unknown rule\")) { /* report pattern and parser.RuleNames */ }","preventionTips":["Regenerate the parser after grammar edits and update rule references in patterns together.","Compile all patterns once at startup to fail fast with a clear message."],"tags":["antlr","csharp","pattern","rule-names","grammar-mismatch"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}