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

UnbufferedCharStream.seek(index) throws UnsupportedOperationException when the computed offset lands at or beyond the number of buffered characters (i >= n). Forward seeks sync() first and clamp to the last available index, so this fires mainly on backward seeks whose target is inside the window arithmetic but outside the actual data, or on defensive edge cases when the buffer cannot satisfy the request (e.g., seeking far past EOF with an exhausted source).

Source

Thrown at runtime/Java/src/org/antlr/v4/runtime/UnbufferedCharStream.java:294

	 */
    @Override
    public void seek(int index) {
		if (index == currentCharIndex) {
			return;
		}

		if (index > currentCharIndex) {
			sync(index - currentCharIndex);
			index = Math.min(index, getBufferStartIndex() + n - 1);
		}

        // index == to bufferStartIndex should set p to 0
        int i = index - getBufferStartIndex();
        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 "+getBufferStartIndex()+".."+(getBufferStartIndex()+n));
        }

		p = i;
		currentCharIndex = index;
		if (p == 0) {
			lastChar = lastCharBufferStart;
		}
		else {
			lastChar = data[p-1];
		}
    }

    @Override
    public int size() {
        throw new UnsupportedOperationException("Unbuffered stream cannot know its size");
    }

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Clamp the target to the last valid index before seeking: index = Math.min(index, lastIndexKnown)
  2. Verify the target is within the marked/retained window and at or before EOF before calling seek
  3. Use a buffered stream if you need position-jump semantics on the whole input

Example fix

// before
stream.seek(requestedOffset); // may land past buffered data / EOF

// after
int last = stream.getBufferStartIndex() + /* buffered count via LA probing */ 0;
// safer: only seek within a held mark's window
int m = stream.mark();
try {
    int target = Math.min(requestedOffset, stream.index());
    stream.seek(target);
} finally { stream.release(m); }
Defensive patterns

Strategy: validation

Validate before calling

int target = Math.min(requestedIndex, lastKnownIndex); // clamp to at-or-before EOF
if (target < stream.index()) {
    // backward seek: ensure within the retained window (see error 52 guard)
}
stream.seek(target);

Try / catch

try { stream.seek(target); }
catch (UnsupportedOperationException e) { /* clamp target into the buffer window and retry once */ }

Prevention

When it happens

Trigger: seek(target) where target exceeds the end of the stream after sync has buffered EOF; seeking while the buffer is empty or was reset concurrently; index arithmetic that skips the early-return and clamp paths.

Common situations: Calling seek with a user-supplied offset that assumes the input is longer than it is; progress reporting code seeking to percentage positions in the stream.

Related errors


AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14). Data as JSON: /api/errors/c80023c8a7ddaac4. Report an issue: GitHub.