antlr/antlr4 · critical · Exception
Precedence predicates are not supported in lexers.
Error message
Precedence predicates are not supported in lexers.
What it means
LexerATNSimulator.AdaptivePredict/closure path throws when it encounters a PRECEDENCE transition while running a lexer ATN. Precedence predicates ({p>N}?) are a parser-only feature: they resolve left-recursive rule precedence, which has no meaning during tokenization. If a serialized lexer ATN contains a precedence transition, the ATN itself is malformed for lexing purposes and the simulator refuses to continue.
Source
Thrown at runtime/CSharp/src/Atn/LexerATNSimulator.cs:499
protected LexerATNConfig GetEpsilonTarget(ICharStream input,
LexerATNConfig config,
Transition t,
ATNConfigSet configs,
bool speculative,
bool treatEofAsEpsilon)
{
LexerATNConfig c = null;
switch (t.TransitionType)
{
case TransitionType.RULE:
RuleTransition ruleTransition = (RuleTransition)t;
PredictionContext newContext = new SingletonPredictionContext(config.context, ruleTransition.followState.stateNumber);
c = new LexerATNConfig(config, t.target, newContext);
break;
case TransitionType.PRECEDENCE:
throw new Exception("Precedence predicates are not supported in lexers.");
case TransitionType.PREDICATE:
/* Track traversing semantic predicates. If we traverse,
we cannot add a DFA state for this "reach" computation
because the DFA would not test the predicate again in the
future. Rather than creating collections of semantic predicates
like v3 and testing them on prediction, v4 will test them on the
fly all the time using the ATN not the DFA. This is slower but
semantically it's not used that often. One of the key elements to
this predicate mechanism is not adding DFA states that see
predicates immediately afterwards in the ATN. For example,
a : ID {p1}? | ID {p2}? ;
should create the start state for rule 'a' (to save start state
competition), but should not create target of ID state. The
collection of ATN states the following ID references includes
states reached by traversing predicates. Since this is when weView on GitHub (pinned to 7d5770395b)
Solutions
- Check atn.grammarType == ATNType.Lexer before constructing LexerInterpreter/LexerATNSimulator, and use the lexer's own serialized ATN
- Remove precedence predicates ({p>...}?) from lexer rules; if you need precedence-dependent lexing, restructure so the parser handles it
- Regenerate the grammar with the ANTLR tool version matching your runtime to rule out malformed serialization
Example fix
// before
// atn actually came from MyParser (grammar MyParser; parser rules...)
var lexInterp = new LexerInterpreter("MyLexer", vocab, ruleNames, modeNames, atn, input); // throws at runtime
// after
if (atn.grammarType != ATNType.Lexer)
throw new InvalidOperationException("Expected a lexer ATN, got " + atn.grammarType);
var lexInterp = new LexerInterpreter("MyLexer", vocab, ruleNames, modeNames, atn, input); Defensive patterns
Strategy: validation
Validate before calling
if (atn.grammarType != ATNType.Lexer)
throw new InvalidOperationException($"Expected lexer ATN but got {atn.grammarType}; check which serialized ATN you passed."); Type guard
static bool IsLexerAtn(ATN atn) => atn != null && atn.grammarType == ATNType.Lexer;
Prevention
- Keep lexer and parser serialized ATNs in separately named members
- Never use precedence predicates in lexer rules; run grammar through the tool with warnings-as-errors
When it happens
Trigger: A lexer ATN containing a TransitionType.PRECEDENCE edge is executed by LexerATNSimulator (the closure loop hits the PRECEDENCE case and throws). Typically caused by building a LexerInterpreter or LexerATNSimulator over an ATN that was actually serialized from a parser grammar, or by a grammar/tool bug that embedded precedence predicates in lexer rules.
Common situations: Passing a parser ATN into a lexer interpreter (mixing up the two serialized ATNs); using a left-recursive-rule grammar file as both lexer and parser source; tool/runtime version skew producing malformed serialized lexer ATNs.
Related errors
- The specified lexer action type {0} is not valid.
- precpred(_ctx, %d)
- Precedence predicates are not supported in lexers.
- Invalid state number.
- The object is read only.
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/d2ea48b24485870e.
Report an issue: GitHub.