{"record":{"id":"fde1d6ef09347e41","repo":"antlr/antlr4","slug":"lexernoviablealtexception","errorCode":null,"errorMessage":"LexerNoViableAltException('{}')","messagePattern":"LexerNoViableAltException\\('(.+?)'\\)","errorType":"exception","errorClass":"LexerNoViableAltException","httpStatus":null,"severity":"error","filePath":"runtime/Python3/src/antlr4/atn/LexerATNSimulator.py","lineNumber":254,"sourceCode":"                # cause a failover from DFA later.\n               self. addDFAEdge(s, t, self.ERROR)\n\n            # stop when we can't match any more char\n            return self.ERROR\n\n        # Add an edge from s to target DFA found/created for reach\n        return self.addDFAEdge(s, t, cfgs=reach)\n\n    def failOrAccept(self, prevAccept:SimState , input:InputStream, reach:ATNConfigSet, t:int):\n        if self.prevAccept.dfaState is not None:\n            lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor\n            self.accept(input, lexerActionExecutor, self.startIndex, prevAccept.index, prevAccept.line, prevAccept.column)\n            return prevAccept.dfaState.prediction\n        else:\n            # if no accept and EOF is first char, return EOF\n            if t==Token.EOF and input.index==self.startIndex:\n                return Token.EOF\n            raise LexerNoViableAltException(self.recog, input, self.startIndex, reach)\n\n    # Given a starting configuration set, figure out all ATN configurations\n    #  we can reach upon input {@code t}. Parameter {@code reach} is a return\n    #  parameter.\n    def getReachableConfigSet(self, input:InputStream, closure:ATNConfigSet, reach:ATNConfigSet, t:int):\n        # this is used to skip processing for configs which have a lower priority\n        # than a config that already reached an accept state for the same rule\n        skipAlt = ATN.INVALID_ALT_NUMBER\n        for cfg in closure:\n            currentAltReachedAcceptState = ( cfg.alt == skipAlt )\n            if currentAltReachedAcceptState and cfg.passedThroughNonGreedyDecision:\n                continue\n\n            if LexerATNSimulator.debug:\n                print(\"testing\", self.getTokenName(t), \"at\",  str(cfg))\n\n            for trans in cfg.state.transitions:          # for each transition\n                target = self.getReachableTarget(trans, t)","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Python3/src/antlr4/atn/LexerATNSimulator.py#L236-L272","documentation":"LexerATNSimulator.failOrAccept() raises LexerNoViableAltException when the DFA could not reach any accept state for the input from startIndex (and the input is not the immediate-EOF case, which returns Token.EOF). It is the lexer-side analogue of a syntax error: no lexer rule alternative matches the remaining characters, so no token can be produced.","triggerScenarios":"Input at the error position matches no lexer rule — an unrecognized character or sequence (e.g. '$' when the grammar has no rule covering it), or a mode-specific grammar receiving input not covered in the current lexer mode.","commonSituations":"Missing a catch-all rule like UNRECOGNIZED: . ; in the lexer; switching lexer modes (pushMode) and hitting characters only valid in another mode; UTF-8/BOM bytes or smart quotes in input when the grammar only covers ASCII; feeding the parser's lexer a stream of a different file type.","solutions":["Add a catch-all lexer rule (e.g. UNEXPECTED: . ;) or explicitly enumerate the stray characters so the lexer can always produce a token, then handle it in the parser/listener.","Attach a custom error listener (lexer.removeErrorListeners(); lexer.addErrorListener(...)) to report line/column instead of crashing.","For mode grammars, audit pushMode/popMode pairing so each mode covers all inputs it can receive.","Sanitize/validate input encoding (strip BOM, normalize unicode punctuation) before lexing."],"exampleFix":"// before (grammar)\nID: [a-zA-Z]+ ; INT: [0-9]+ ; WS: [ \\t\\r\\n]+ -> skip ;  // '$' -> LexerNoViableAltException\n\n// after (grammar)\nID: [a-zA-Z]+ ; INT: [0-9]+ ; WS: [ \\t\\r\\n]+ -> skip ;\nUNEXPECTED: . ;  // always matches one char; report in parser/listener","handlingStrategy":"try-catch","validationCode":"# Grammar-level guard: guarantee the lexer can always match something\n# UNEXPECTED: . ;   // add last in the lexer grammar\n\n# Code-level guard: pre-scan input characters against a coverage set\nallowed = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 \\t\\r\\n')\nif any(ch not in allowed for ch in text):\n    raise ValueError('input contains characters the lexer grammar cannot match')","typeGuard":null,"tryCatchPattern":"from antlr4.error.Errors import LexerNoViableAltException\nclass CollectingErrorListener(ErrorListener):\n    def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):\n        errors.append((line, column, msg))\n\nlexer.removeErrorListeners()\nlexer.addErrorListener(CollectingErrorListener())\ntokens = lexer  # errors collected instead of raising; inspect lexer.symbolicNames for the offending text","preventionTips":["Add a trailing catch-all lexer rule (UNEXPECTED: . ;) so lexing never fails outright","Install a custom error listener to capture line/column instead of exceptions","Audit pushMode/popMode pairing in multi-mode grammars","Strip BOMs and normalize exotic unicode before lexing"],"tags":["antlr4","python","lexer","no-viable-alt","grammar"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}