{"record":{"id":"339c11501dfab319","repo":"antlr/antlr4","slug":"cannot-seek-to-negative-index-index","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/UnbufferedCharStream.java","lineNumber":291,"sourceCode":"\n\t/** Seek to absolute character index, which might not be in the current\n\t *  sliding window.  Move {@code p} to {@code index-bufferStartIndex}.\n\t */\n    @Override\n    public void seek(int index) {\n\t\tif (index == currentCharIndex) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (index > currentCharIndex) {\n\t\t\tsync(index - currentCharIndex);\n\t\t\tindex = Math.min(index, getBufferStartIndex() + n - 1);\n\t\t}\n\n        // index == to bufferStartIndex should set p to 0\n        int i = index - getBufferStartIndex();\n        if ( i < 0 ) {\n\t\t\tthrow new IllegalArgumentException(\"cannot seek to negative index \" + index);\n\t\t}\n\t\telse if (i >= n) {\n            throw new UnsupportedOperationException(\"seek to index outside buffer: \"+\n                    index+\" not in \"+getBufferStartIndex()+\"..\"+(getBufferStartIndex()+n));\n        }\n\n\t\tp = i;\n\t\tcurrentCharIndex = index;\n\t\tif (p == 0) {\n\t\t\tlastChar = lastCharBufferStart;\n\t\t}\n\t\telse {\n\t\t\tlastChar = data[p-1];\n\t\t}\n    }\n\n    @Override\n    public int size() {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/UnbufferedCharStream.java#L273-L309","documentation":"UnbufferedCharStream.seek(index) computes the offset of index from the buffer start; a negative offset means the requested character position lies before the retained window, which an unbuffered stream cannot re-read. It throws IllegalArgumentException ('cannot seek to negative index') rather than silently re-reading discarded data.","triggerScenarios":"seek(0) or any backward seek after the buffer has advanced past the target (markers released, earlier chars discarded); seek to an index below the current bufferStartIndex after long forward consumption.","commonSituations":"Error reporting or token-highlighting code that rewinds to re-extract text after parsing has moved on; generic stream utilities that assume seek(0) is always legal; migrating code from ANTLRInputStream (buffered) to UnbufferedCharStream for memory reasons.","solutions":["Hold a mark() across the region you may need to re-seek into, and release it only when done","Extract the text you will need later (via getText) before the buffer moves past it","Switch to a buffered stream (ANTLRInputStream / fromReader with buffering) if arbitrary backward seeks are required"],"exampleFix":"// before\n// ... lex far ahead ...\nstream.seek(0); // IllegalArgumentException: 0 < bufferStartIndex\n\n// after\nint m = stream.mark();\ntry {\n    // ... lex, then rewind safely ...\n    stream.seek(stream.index() ); // stay within marked window\n} finally {\n    stream.release(m);\n}","handlingStrategy":"validation","validationCode":"// bufferStartIndex == index() - (buffered count); track a floor via marks\nint floor = markedFloorIndex; // recorded at mark() time\nif (index < floor) {\n    throw new UnsupportedOperationException(\"target \" + index + \" was discarded; use a buffered stream\");\n}\nstream.seek(index);","typeGuard":null,"tryCatchPattern":"try { stream.seek(target); }\ncatch (IllegalArgumentException | UnsupportedOperationException e) { /* re-open input in a buffered stream and retry the whole parse */ }","preventionTips":["Never seek backward in an unbuffered stream without a live mark","Extract text before the window moves past it","Use ANTLRInputStream when rewind semantics are needed"],"tags":["antlr","char-stream","seek","backward","buffer"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}