{"record":{"id":"c2c126a32be2f053","repo":"antlr/antlr4","slug":"invalid-state-number","errorCode":null,"errorMessage":"Invalid state number.","messagePattern":"Invalid state number\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/atn/ATN.java","lineNumber":168,"sourceCode":"\t * The big difference is that with just the input, the parser could\n\t * land right in the middle of a lookahead decision. Getting\n     * all *possible* tokens given a partial input stream is a separate\n     * computation. See https://github.com/antlr/antlr4/issues/1428\n\t *\n\t * For this function, we are specifying an ATN state and call stack to compute\n\t * what token(s) can come next and specifically: outside of a lookahead decision.\n\t * That is what you want for error reporting and recovery upon parse error.\n\t *\n\t * @param stateNumber the ATN state number\n\t * @param context the full parse context\n\t * @return The set of potentially valid input symbols which could follow the\n\t * specified state in the specified context.\n\t * @throws IllegalArgumentException if the ATN does not contain a state with\n\t * number {@code stateNumber}\n\t */\n\tpublic IntervalSet getExpectedTokens(int stateNumber, RuleContext context) {\n\t\tif (stateNumber < 0 || stateNumber >= states.size()) {\n\t\t\tthrow new IllegalArgumentException(\"Invalid state number.\");\n\t\t}\n\n\t\tRuleContext ctx = context;\n\t\tATNState s = states.get(stateNumber);\n\t\tIntervalSet following = nextTokens(s);\n\t\tif (!following.contains(Token.EPSILON)) {\n\t\t\treturn following;\n\t\t}\n\n\t\tIntervalSet expected = new IntervalSet();\n\t\texpected.addAll(following);\n\t\texpected.remove(Token.EPSILON);\n\t\twhile (ctx != null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {\n\t\t\tATNState invokingState = states.get(ctx.invokingState);\n\t\t\tRuleTransition rt = (RuleTransition)invokingState.transition(0);\n\t\t\tfollowing = nextTokens(rt.followState);\n\t\t\texpected.addAll(following);\n\t\t\texpected.remove(Token.EPSILON);","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/atn/ATN.java#L150-L186","documentation":"ATN.getExpectedTokens(stateNumber, context) uses stateNumber as an index into the ATN state list. A negative value or a value at least atn.states.size() cannot identify an ATN state, so the method rejects it before computing the follow set.","triggerScenarios":"Passing a rule index, token type, or generated context constant where an ATN state number is expected; passing -1 from an exception whose offending state is unknown; or using a state number obtained from a different parser/ATN version.","commonSituations":"Custom error reporters that manually call getATN().getExpectedTokens(), mixing generated parser classes from different ANTLR builds, and code that assumes getOffendingState()/getState() is always valid.","solutions":["Validate 0 <= stateNumber < atn.states.size() before the call.","Prefer parser.getExpectedTokens() or RecognitionException.getExpectedTokens(), which use the recognizer's current state.","Ensure the ATN, parser, context, and generated code all come from the same generated parser and ANTLR version.","Treat -1 as unknown state and report a generic error instead of calling the API."],"exampleFix":"// before\nint state = ctx.getRuleIndex(); // wrong: rule index, not ATN state\nIntervalSet expected = atn.getExpectedTokens(state, ctx);\n\n// after\nint state = parser.getState();\nif (state >= 0 && state < atn.states.size()) {\n    IntervalSet expected = atn.getExpectedTokens(state, parser.getContext());\n}","handlingStrategy":"validation","validationCode":"static boolean isValidAtnState(ATN atn, int stateNumber) {\n    return stateNumber >= 0 && stateNumber < atn.states.size();\n}","typeGuard":null,"tryCatchPattern":"try {\n    return atn.getExpectedTokens(stateNumber, context);\n} catch (IllegalArgumentException e) {\n    return new IntervalSet(); // or report that the state is unknown\n}","preventionTips":["Never substitute rule indexes or token types for ATN state numbers.","Use parser.getExpectedTokens() where possible.","Use parser, ATN, and context objects from the same generated version."],"tags":["antlr","java","atn","expected-tokens","validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}