antlr/antlr4 · error · IllegalArgumentException
The ATN must be a lexer ATN.
Error message
The ATN must be a lexer ATN.
What it means
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.
Source
Thrown at runtime/Java/src/org/antlr/v4/runtime/LexerInterpreter.java:49
protected final DFA[] _decisionToDFA;
protected final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
@Deprecated
public LexerInterpreter(String grammarFileName, Collection<String> tokenNames, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) {
this(grammarFileName, VocabularyImpl.fromTokenNames(tokenNames.toArray(new String[0])), ruleNames, new ArrayList<String>(), modeNames, atn, input);
}
@Deprecated
public LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> modeNames, ATN atn, CharStream input) {
this(grammarFileName, vocabulary, ruleNames, new ArrayList<String>(), modeNames, atn, input);
}
public LexerInterpreter(String grammarFileName, Vocabulary vocabulary, Collection<String> ruleNames, Collection<String> channelNames, Collection<String> modeNames, ATN atn, CharStream input) {
super(input);
if (atn.grammarType != ATNType.LEXER) {
throw new IllegalArgumentException("The ATN must be a lexer ATN.");
}
this.grammarFileName = grammarFileName;
this.atn = atn;
this.tokenNames = new String[atn.maxTokenType];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = vocabulary.getDisplayName(i);
}
this.ruleNames = ruleNames.toArray(new String[0]);
this.channelNames = channelNames.toArray(new String[0]);
this.modeNames = modeNames.toArray(new String[0]);
this.vocabulary = vocabulary;
this._decisionToDFA = new DFA[atn.getNumberOfDecisions()];
for (int i = 0; i < _decisionToDFA.length; i++) {
_decisionToDFA[i] = new DFA(atn.getDecisionState(i), i);
}View on GitHub (pinned to 7d5770395b)
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
Example fix
// before
new LexerInterpreter(fileName, vocab, ruleNames, channelNames, modeNames, parserAtn, input); // throws
// after
if (atn.grammarType != ATNType.LEXER) throw new IllegalArgumentException("expected lexer ATN");
new LexerInterpreter(fileName, vocab, ruleNames, channelNames, modeNames, atn, input); Defensive patterns
Strategy: validation
Validate before calling
if (atn.grammarType != ATNType.LEXER) {
throw new IllegalArgumentException("expected a lexer ATN, got " + atn.grammarType);
}
LexerInterpreter li = new LexerInterpreter(name, vocab, ruleNames, channelNames, modeNames, atn, input); Type guard
boolean isLexerAtn(ATN atn) { return atn != null && atn.grammarType == ATNType.LEXER; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid state number.
- Serialized ATN data element[i] = v doesn't fit in 31 bits
- Invalid state number.
- index cannot be negative
- ANTLR 4 caught {} build errors.
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/ba8b3e19e40ffc46.
Report an issue: GitHub.