antlr/antlr4 · error · LexerNoViableAltException
LexerNoViableAltException + symbol
Error message
LexerNoViableAltException + symbol
What it means
NewLexerNoViableAltException is panicked by LexerATNSimulator.failOrAccept() in the Go runtime when the lexer DFA cannot match any rule from the current input position and the input is not EOF at the start index. It means the character(s) at startIndex are not recognized by any lexer rule in the current mode.
Source
Thrown at runtime/Go/antlr/v4/lexer_atn_simulator.go:267
return ATNSimulatorError
}
// Add an edge from s to target DFA found/created for reach
return l.addDFAEdge(s, t, nil, reach)
}
func (l *LexerATNSimulator) failOrAccept(prevAccept *SimState, input CharStream, reach *ATNConfigSet, t int) int {
if l.prevAccept.dfaState != nil {
lexerActionExecutor := prevAccept.dfaState.lexerActionExecutor
l.accept(input, lexerActionExecutor, l.startIndex, prevAccept.index, prevAccept.line, prevAccept.column)
return prevAccept.dfaState.prediction
}
// if no accept and EOF is first char, return EOF
if t == TokenEOF && input.Index() == l.startIndex {
return TokenEOF
}
panic(NewLexerNoViableAltException(l.recog, input, l.startIndex, reach))
}
// getReachableConfigSet when given a starting configuration set, figures out all [ATN] configurations
// we can reach upon input t.
//
// Parameter reach is a return parameter.
func (l *LexerATNSimulator) getReachableConfigSet(input CharStream, closure *ATNConfigSet, reach *ATNConfigSet, t int) {
// l is used to Skip processing for configs which have a lower priority
// than a runtimeConfig that already reached an accept state for the same rule
SkipAlt := ATNInvalidAltNumber
for _, cfg := range closure.configs {
currentAltReachedAcceptState := cfg.GetAlt() == SkipAlt
if currentAltReachedAcceptState && cfg.passedThroughNonGreedyDecision {
continue
}
if runtimeConfig.lexerATNSimulatorDebug {View on GitHub (pinned to 7d5770395b)
Solutions
- Add a catch-all lexer rule such as ERROR : . ; (or skip/tokenize unknown characters) in the grammar
- Pre-validate or sanitize input before lexing
- Wrap lexing in a recover() that converts the panic to an error, and report the offending line/column from the exception
Example fix
// grammar before
// (no rule matches '@')
// grammar after: catch-all rule
// ERROR : . ;
// Go guard
func safeLex(l *antlr.Lexer, ts *antlr.CommonTokenStream) (err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(*antlr.LexerNoViableAltException); ok {
err = fmt.Errorf("bad input at line %d:%d", e.GetLine(), e.GetColumn())
return
}
panic(r)
}
}()
ts.Fill()
return nil
} Defensive patterns
Strategy: try-catch
Type guard
func isLexerNoViableAlt(r interface{}) bool {
_, ok := r.(*antlr.LexerNoViableAltException)
return ok
} Try / catch
func safeFill(ts *antlr.CommonTokenStream) (err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(*antlr.LexerNoViableAltException); ok {
err = fmt.Errorf("lexer failed at line %d, col %d", e.GetLine(), e.GetColumn())
return
}
panic(r)
}
}()
ts.Fill()
return nil
} Prevention
- Add an ERROR : . ; catch-all rule to the lexer grammar
- Pre-sanitize input for stray characters and control the lexer mode stack
- Always recover() around lexing in Go; the runtime panics instead of throwing
When it happens
Trigger: Feeding input to the generated Go lexer containing a character with no matching lexer rule (e.g. '@' when no rule accepts it), or reaching a mode whose rules do not cover the next character. The Go runtime panics rather than throwing, so unrecovered it crashes the program.
Common situations: Missing catch-all lexer rule, unexpected unicode/whitespace in input, wrong mode after a pushMode, or feeding binary data to a text lexer.
Related errors
- nextToken requires a non-null input stream.
- Parser can't discover a lexer to use
- The specified lexer action type %s is not valid.
- The specified lexer action type %s is not valid.
- Precedence predicates are not supported in lexers.
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/31747c540fe7eb59.
Report an issue: GitHub.