{"record":{"id":"6d44125c75d34fd2","repo":"antlr/antlr4","slug":"interval-interval-not-in-token-buffer-window-b","errorCode":null,"errorMessage":"interval {interval} not in token buffer window: {bufferStartIndex}..{bufferStopIndex}","messagePattern":"interval (.+?) not in token buffer window: (.+?)\\.\\.(.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/UnbufferedTokenStream.java","lineNumber":292,"sourceCode":"\tpublic int size() {\n\t\tthrow new UnsupportedOperationException(\"Unbuffered stream cannot know its size\");\n\t}\n\n\t@Override\n\tpublic String getSourceName() {\n\t\treturn tokenSource.getSourceName();\n\t}\n\n\n\t@Override\n\tpublic String getText(Interval interval) {\n\t\tint bufferStartIndex = getBufferStartIndex();\n\t\tint bufferStopIndex = bufferStartIndex + tokens.length - 1;\n\n\t\tint start = interval.a;\n\t\tint stop = interval.b;\n\t\tif (start < bufferStartIndex || stop > bufferStopIndex) {\n\t\t\tthrow new UnsupportedOperationException(\"interval \"+interval+\" not in token buffer window: \"+\n\t\t\t\t\t\t\t\t\t\t\t\t\tbufferStartIndex+\"..\"+bufferStopIndex);\n\t\t}\n\n\t\tint a = start - bufferStartIndex;\n\t\tint b = stop - bufferStartIndex;\n\n\t\tStringBuilder buf = new StringBuilder();\n\t\tfor (int i = a; i <= b; i++) {\n\t\t\tToken t = tokens[i];\n\t\t\tbuf.append(t.getText());\n\t\t}\n\n\t\treturn buf.toString();\n\t}\n\n\tprotected final int getBufferStartIndex() {\n\t\treturn currentTokenIndex - p;\n\t}","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/UnbufferedTokenStream.java#L274-L310","documentation":"UnbufferedTokenStream.getText(Interval) can return text only from tokens still present in its allocated buffer window. It rejects intervals whose start is before bufferStartIndex or whose stop is beyond bufferStartIndex + tokens.length - 1. Once old tokens are flushed, their text cannot be recovered.","triggerScenarios":"Calling getText(ctx.getSourceInterval()), getText(Token,Token), or getText(Interval) after earlier tokens were flushed without a marker; requesting a stop token that has not been buffered; or passing an interval from a parse tree whose tokens precede the current buffer start.","commonSituations":"Extracting text from a parse tree after parsing completed, using UnbufferedTokenStream to save memory, and generic reporting/rewriting utilities that request arbitrary intervals.","solutions":["Use CommonTokenStream/BufferedTokenStream when parse-tree text extraction is required.","Call getText while the interval is still buffered and keep a mark active during lookahead/backtracking.","Load enough lookahead before requesting future intervals.","Recreate the token stream if text from already-discarded tokens is required."],"exampleFix":"// before\nUnbufferedTokenStream<Token> tokens = new UnbufferedTokenStream<>(lexer);\nparser.setTokenStream(tokens);\nParseTree tree = parser.start();\nString text = tokens.getText(tree.getSourceInterval()); // earlier tokens may be gone\n\n// after\nCommonTokenStream tokens = new CommonTokenStream(lexer);\nparser.setTokenStream(tokens);\nParseTree tree = parser.start();\nString text = tokens.getText(tree.getSourceInterval());","handlingStrategy":"validation","validationCode":"static boolean intervalLooksRetained(UnbufferedTokenStream<Token> tokens, Interval interval) {\n    if (interval.a < 0 || interval.b < interval.a) return false;\n    int current = tokens.index();\n    if (interval.b >= current) {\n        tokens.LT(interval.b - current + 1); // load ahead, clamps to EOF\n    }\n    try {\n        tokens.get(interval.a);\n        tokens.get(interval.b);\n        return true;\n    } catch (IndexOutOfBoundsException e) {\n        return false;\n    }\n}","typeGuard":"static boolean supportsArbitraryGetText(TokenStream tokens) {\n    return tokens instanceof BufferedTokenStream;\n}","tryCatchPattern":"try {\n    return tokens.getText(interval);\n} catch (UnsupportedOperationException e) {\n    // requested interval left the buffer; retain a buffer or re-lex the source\n}","preventionTips":["Extract needed text before old tokens are flushed or while a mark is active.","Use CommonTokenStream for parse-tree text extraction.","Avoid range utilities that assume the whole token stream is retained."],"tags":["antlr","java","token-stream","text","interval","buffer"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}