{"record":{"id":"98ad624e4776b22e","repo":"antlr/antlr4","slug":"cannot-seek-to-negative-index-index-98ad62","errorCode":null,"errorMessage":"cannot seek to negative index {index}","messagePattern":"cannot seek to negative index (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/UnbufferedTokenStream.java","lineNumber":256,"sourceCode":"\tpublic int index() {\n\t\treturn currentTokenIndex;\n\t}\n\n\t@Override\n\tpublic void seek(int index) { // seek to absolute index\n\t\tif (index == currentTokenIndex) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (index > currentTokenIndex) {\n\t\t\tsync(index - currentTokenIndex);\n\t\t\tindex = Math.min(index, getBufferStartIndex() + n - 1);\n\t\t}\n\n\t\tint bufferStartIndex = getBufferStartIndex();\n\t\tint i = index - bufferStartIndex;\n\t\tif ( i < 0 ) {\n\t\t\tthrow new IllegalArgumentException(\"cannot seek to negative index \" + index);\n\t\t}\n\t\telse if (i >= n) {\n\t\t\tthrow new UnsupportedOperationException(\"seek to index outside buffer: \"+\n\t\t\t\t\t\t\t\t\t\t\t\t\tindex+\" not in \"+ bufferStartIndex +\"..\"+(bufferStartIndex +n));\n\t\t}\n\n\t\tp = i;\n\t\tcurrentTokenIndex = index;\n\t\tif (p == 0) {\n\t\t\tlastToken = lastTokenBufferStart;\n\t\t}\n\t\telse {\n\t\t\tlastToken = tokens[p-1];\n\t\t}\n\t}\n\n\t@Override\n\tpublic int size() {","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/UnbufferedTokenStream.java#L238-L274","documentation":"UnbufferedTokenStream.seek(index) accepts an absolute index only inside its retained moving window. It computes i = index - bufferStartIndex; i < 0 means the requested token was already flushed. Despite the wording, the printed index can be non-negative: seek(0) after the buffer start advanced also produces this exception.","triggerScenarios":"Calling seek(0) after consuming tokens without an active marker; seeking backward to any index before getBufferStartIndex(); passing a negative index; or calling a reset/backtracking routine after the unbuffered stream has flushed old tokens.","commonSituations":"Porting random-access code from BufferedTokenStream to UnbufferedTokenStream, replaying a token range after parsing, and custom backtracking that forgot to mark the region before consuming.","solutions":["Call mark() before consuming tokens that you may need to seek back to; release it only after backtracking is complete.","For random access or seek(0), use BufferedTokenStream/CommonTokenStream instead.","Validate index >= 0 and never seek before the point where the stream was constructed/marked.","Recreate the token source and stream when old tokens must be replayed and were not retained."],"exampleFix":"// before\nwhile (tokens.LA(1) != Token.EOF) tokens.consume();\ntokens.seek(0); // old tokens were flushed\n\n// after\nint marker = tokens.mark(); // mark before consuming\ntry {\n    while (tokens.LA(1) != Token.EOF) tokens.consume();\n    tokens.seek(0);\n} finally {\n    tokens.release(marker);\n}","handlingStrategy":"validation","validationCode":"static boolean canSeek(UnbufferedTokenStream<Token> tokens, int index, boolean haveProtectingMark) {\n    if (index < 0) return false;\n    return index >= tokens.index() || haveProtectingMark;\n}","typeGuard":"static boolean supportsArbitraryBackwardSeek(TokenStream tokens) {\n    return tokens instanceof BufferedTokenStream;\n}","tryCatchPattern":"try {\n    tokens.seek(index);\n} catch (IllegalArgumentException e) {\n    // token is outside the retained unbuffered window; replay from a new stream\n}","preventionTips":["Mark before consuming any token you may revisit.","Use BufferedTokenStream for seek(0) and arbitrary backtrack scenarios.","Do not call stream reset routines after releasing the protecting mark."],"tags":["antlr","java","token-stream","seek","backtracking"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}