antlr/antlr4 · error · UnsupportedOperationException
seek to index outside buffer: {index} not in {bufferStartInd
Error message
seek to index outside buffer: {index} not in {bufferStartIndex}..{bufferStartIndex+n} What it means
After syncing and clamping a forward seek, UnbufferedTokenStream verifies that the resulting relative position is still inside bufferStartIndex..bufferStartIndex+n. If it is not, the stream cannot honor the seek without retaining tokens, so it throws UnsupportedOperationException. In normal operation forward seeks are clamped to EOF, so this guard also catches inconsistent state or unsupported random access.
Source
Thrown at runtime/Java/src/org/antlr/v4/runtime/UnbufferedTokenStream.java:259
@Override
public void seek(int index) { // seek to absolute index
if (index == currentTokenIndex) {
return;
}
if (index > currentTokenIndex) {
sync(index - currentTokenIndex);
index = Math.min(index, getBufferStartIndex() + n - 1);
}
int bufferStartIndex = getBufferStartIndex();
int i = index - bufferStartIndex;
if ( i < 0 ) {
throw new IllegalArgumentException("cannot seek to negative index " + index);
}
else if (i >= n) {
throw new UnsupportedOperationException("seek to index outside buffer: "+
index+" not in "+ bufferStartIndex +".."+(bufferStartIndex +n));
}
p = i;
currentTokenIndex = index;
if (p == 0) {
lastToken = lastTokenBufferStart;
}
else {
lastToken = tokens[p-1];
}
}
@Override
public int size() {
throw new UnsupportedOperationException("Unbuffered stream cannot know its size");
}
View on GitHub (pinned to 7d5770395b)
Solutions
- Use BufferedTokenStream or CommonTokenStream for random-access seeks.
- Keep a marker active for the whole region in which seeks are allowed on an unbuffered stream.
- Seek only to indexes already represented in the buffer and never after release of the protecting mark.
- If subclassing UnbufferedTokenStream, preserve its p, n, and currentTokenIndex invariants.
Example fix
// before UnbufferedTokenStream<Token> tokens = new UnbufferedTokenStream<>(lexer); tokens.seek(requestedTokenIndex); // may fall outside retained window // after CommonTokenStream tokens = new CommonTokenStream(lexer); tokens.seek(requestedTokenIndex); // buffered until EOF
Defensive patterns
Strategy: try-catch
Type guard
static boolean supportsRandomAccess(TokenStream tokens) {
return tokens instanceof BufferedTokenStream;
} Try / catch
try {
tokens.seek(index);
} catch (UnsupportedOperationException e) {
throw new IllegalArgumentException("Random access required; use BufferedTokenStream", e);
} Prevention
- Choose the token-stream implementation based on required access pattern.
- Keep marked regions open during all seeks.
- Do not assume IntStream.seek is random-access for every implementation.
When it happens
Trigger: Calling seek() with an absolute index that is not represented by the current buffer window after sync; using an UnbufferedTokenStream subclass or stream manipulation that leaves p/currentTokenIndex inconsistent; or generic code assuming every TokenStream supports arbitrary seeks.
Common situations: Generic IntStream utilities, custom lookahead/backtracking engines, and code migrated from BufferedTokenStream. It commonly indicates the chosen stream implementation does not provide the required access model rather than a grammar bug.
Related errors
- cannot seek to negative index {index}
- get({i}) outside buffer: {bufferStartIndex}..{bufferStartInd
- cannot consume EOF
- release() called with an invalid marker.
- Unbuffered stream cannot know its size
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/a995f7ddec37f673.
Report an issue: GitHub.