{"record":{"id":"54c3489949bca59d","repo":"antlr/antlr4","slug":"start-or-stop-not-in-0","errorCode":null,"errorMessage":"start {} or stop {} not in 0..{}","messagePattern":"start (.+?) or stop (.+?) not in 0\\.\\.(.+?)","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/BufferedTokenStream.java","lineNumber":281,"sourceCode":"        fetchedEOF = false;\n    }\n\n    public List<Token> getTokens() { return tokens; }\n\n    public List<Token> getTokens(int start, int stop) {\n        return getTokens(start, stop, null);\n    }\n\n    /** Given a start and stop index, return a List of all tokens in\n     *  the token type BitSet.  Return null if no tokens were found.  This\n     *  method looks at both on and off channel tokens.\n     */\n    public List<Token> getTokens(int start, int stop, Set<Integer> types) {\n        lazyInit();\n\t\tif ( start<0 || stop>=tokens.size() ||\n\t\t\t stop<0  || start>=tokens.size() )\n\t\t{\n\t\t\tthrow new IndexOutOfBoundsException(\"start \"+start+\" or stop \"+stop+\n\t\t\t\t\t\t\t\t\t\t\t\t\" not in 0..\"+(tokens.size()-1));\n\t\t}\n        if ( start>stop ) return null;\n\n        // list = tokens[start:stop]:{T t, t.getType() in types}\n        List<Token> filteredTokens = new ArrayList<Token>();\n        for (int i=start; i<=stop; i++) {\n            Token t = tokens.get(i);\n            if ( types==null || types.contains(t.getType()) ) {\n                filteredTokens.add(t);\n            }\n        }\n        if ( filteredTokens.isEmpty() ) {\n            filteredTokens = null;\n        }\n        return filteredTokens;\n    }\n","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/BufferedTokenStream.java#L263-L299","documentation":"getTokens(int start, int stop, Set<Integer> types) requires both endpoints to lie inside the current token buffer (0..size()-1); otherwise it throws IndexOutOfBoundsException. Note the asymmetry with the two-argument get(start, stop), which returns null for negative bounds instead of throwing. lazyInit() runs first, but that only guarantees the first token exists, not that the whole range is fetched.","triggerScenarios":"Calling getTokens(0, tokens.size(), null) (stop one past the end); passing stop from an unfilled stream's estimated size; passing -1 sentinels that the two-arg overload tolerates but this overload rejects.","commonSituations":"Filters over token types (e.g. collecting all comment or string tokens) written against the wrong overload's semantics; code migrated from get(start, stop) that relied on null returns for invalid ranges; highlighting code that clamps indices incorrectly.","solutions":["Clamp: int stop = Math.min(stop, tokens.size() - 1) and reject start < 0 before calling","Call tokens.fill() before ranged queries so size() reflects the whole input","Return early (or null) yourself when start > stop or bounds are invalid instead of relying on the exception"],"exampleFix":"// before\nList<Token> all = tokens.getTokens(0, tokens.size(), types); // throws\n\n// after\ntokens.fill();\nList<Token> all = tokens.getTokens(0, tokens.size() - 1, types);","handlingStrategy":"validation","validationCode":"tokens.fill();\nint stop = Math.min(requestedStop, tokens.size() - 1);\nint start = Math.max(requestedStart, 0);\nif (start <= stop) { List<Token> ts = tokens.getTokens(start, stop, types); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp both endpoints into 0..size()-1 before calling getTokens","Remember the 3-arg overload throws where the 2-arg overload returns null","fill() first when querying ranges near the end of input"],"tags":["antlr","token-stream","index-out-of-bounds","range"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}