{"record":{"id":"ba8b3e19e40ffc46","repo":"antlr/antlr4","slug":"the-atn-must-be-a-lexer-atn","errorCode":null,"errorMessage":"The ATN must be a lexer ATN.","messagePattern":"The ATN must be a lexer ATN\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/LexerInterpreter.java","lineNumber":49,"sourceCode":"\tprotected final DFA[] _decisionToDFA;\n\tprotected final PredictionContextCache _sharedContextCache =\n\t\tnew PredictionContextCache();\n\n\t@Deprecated\n\tpublic LexerInterpreter(String grammarFileName, Collection<String> tokenNames, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) {\n\t\tthis(grammarFileName, VocabularyImpl.fromTokenNames(tokenNames.toArray(new String[0])), ruleNames, new ArrayList<String>(), modeNames, atn, input);\n\t}\n\n\t@Deprecated\n\tpublic LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) {\n\t\tthis(grammarFileName, vocabulary, ruleNames, new ArrayList<String>(), modeNames, atn, input);\n\t}\n\n\tpublic LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> channelNames, Collection<String> modeNames, ATN atn, CharStream input) {\n\t\tsuper(input);\n\n\t\tif (atn.grammarType != ATNType.LEXER) {\n\t\t\tthrow new IllegalArgumentException(\"The ATN must be a lexer ATN.\");\n\t\t}\n\n\t\tthis.grammarFileName = grammarFileName;\n\t\tthis.atn = atn;\n\t\tthis.tokenNames = new String[atn.maxTokenType];\n\t\tfor (int i = 0; i < tokenNames.length; i++) {\n\t\t\ttokenNames[i] = vocabulary.getDisplayName(i);\n\t\t}\n\n\t\tthis.ruleNames = ruleNames.toArray(new String[0]);\n\t\tthis.channelNames = channelNames.toArray(new String[0]);\n\t\tthis.modeNames = modeNames.toArray(new String[0]);\n\t\tthis.vocabulary = vocabulary;\n\n\t\tthis._decisionToDFA = new DFA[atn.getNumberOfDecisions()];\n\t\tfor (int i = 0; i < _decisionToDFA.length; i++) {\n\t\t\t_decisionToDFA[i] = new DFA(atn.getDecisionState(i), i);\n\t\t}","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/LexerInterpreter.java#L31-L67","documentation":"LexerInterpreter validates that the ATN passed to it has grammarType == ATNType.LEXER, otherwise it throws IllegalArgumentException. A LexerInterpreter drives lexer ATN transitions (token rule matching), so a parser ATN is structurally unusable and would fail later in confusing ways — hence the fail-fast check. The interpreter is used for grammars loaded at runtime from serialized ATNs (e.g. from a .tokens/.interp or tool-generated data) rather than generated code.","triggerScenarios":"new LexerInterpreter(name, vocab, ruleNames, channelNames, modeNames, parserAtn, input) where atn came from ATNDeserializer on a parser's serialized ATN; mixing up the lexer and parser ATN fields when loading grammar metadata by hand.","commonSituations":"Building generic grammar-runner tools (like antlr4-parse or IDE plugins) that deserialize ATNs at runtime; copy-paste errors when wiring Grammar objects; loading the wrong .interp/serialized field order after an ANTLR version change.","solutions":["Pass the ATN whose grammarType is ATNType.LEXER — verify with atn.grammarType == ATNType.LEXER before constructing","When loading from a Grammar/tool artifact, take the lexer ATN for LexerInterpreter and the parser ATN for ParserInterpreter","Use ParserInterpreter for parser ATNs; if you actually need a lexer for that grammar, load the lexer's serialized ATN instead"],"exampleFix":"// before\nnew LexerInterpreter(fileName, vocab, ruleNames, channelNames, modeNames, parserAtn, input); // throws\n\n// after\nif (atn.grammarType != ATNType.LEXER) throw new IllegalArgumentException(\"expected lexer ATN\");\nnew LexerInterpreter(fileName, vocab, ruleNames, channelNames, modeNames, atn, input);","handlingStrategy":"validation","validationCode":"if (atn.grammarType != ATNType.LEXER) {\n  throw new IllegalArgumentException(\"expected a lexer ATN, got \" + atn.grammarType);\n}\nLexerInterpreter li = new LexerInterpreter(name, vocab, ruleNames, channelNames, modeNames, atn, input);","typeGuard":"boolean isLexerAtn(ATN atn) { return atn != null && atn.grammarType == ATNType.LEXER; }","tryCatchPattern":null,"preventionTips":["Check atn.grammarType == ATNType.LEXER before building a LexerInterpreter","Keep lexer and parser ATNs in clearly named fields when loading grammars at runtime","Use ParserInterpreter only with parser-type ATNs"],"tags":["antlr","lexer-interpreter","atn","validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}