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

  1. Pass the ATN whose grammarType is ATNType.LEXER — verify with atn.grammarType == ATNType.LEXER before constructing
  2. When loading from a Grammar/tool artifact, take the lexer ATN for LexerInterpreter and the parser ATN for ParserInterpreter
  3. 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

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


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