antlr/antlr4 · error · IllegalArgumentException

the interval extends past the end of the stream

Error message

the interval extends past the end of the stream

What it means

In UnbufferedCharStream.getText(Interval), once the EOF marker has been buffered (data[n-1] == Character.MAX_VALUE), the stream knows the true end of input. If the requested interval's end (a + length) extends beyond that known end, it throws IllegalArgumentException 'the interval extends past the end of the stream' — there is no text beyond EOF to return.

Source

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

    @Override
    public String getSourceName() {
		if (name == null || name.isEmpty()) {
			return UNKNOWN_SOURCE_NAME;
		}

		return name;
	}

	@Override
	public String getText(Interval interval) {
		if (interval.a < 0 || interval.b < interval.a - 1) {
			throw new IllegalArgumentException("invalid interval");
		}

		int bufferStartIndex = getBufferStartIndex();
		if (n > 0 && data[n - 1] == Character.MAX_VALUE) {
			if (interval.a + interval.length() > bufferStartIndex + n) {
				throw new IllegalArgumentException("the interval extends past the end of the stream");
			}
		}

		if (interval.a < bufferStartIndex || interval.b >= bufferStartIndex + n) {
			throw new UnsupportedOperationException("interval "+interval+" outside buffer: "+
			                    bufferStartIndex+".."+(bufferStartIndex+n-1));
		}
		// convert from absolute to local index
		int i = interval.a - bufferStartIndex;
		return new String(data, i, interval.length());
	}

	protected final int getBufferStartIndex() {
		return currentCharIndex - p;
	}
}

View on GitHub (pinned to 7d5770395b)

Solutions

  1. Clamp b to the last character index (bufferStartIndex + n - 1) before calling when EOF is known to be buffered
  2. Derive intervals from tokens of the same parse so they cannot exceed the input
  3. Treat the empty string as the answer when a >= end of stream

Example fix

// before
String t = stream.getText(Interval.of(a, a + width - 1)); // overshoots on short input

// after
int end = Math.min(a + width - 1, lastIndexOfStream); // track last index as you read
String t = (a > end) ? "" : stream.getText(Interval.of(a, end));
Defensive patterns

Strategy: validation

Validate before calling

int end = Math.min(b, knownLastIndex); // clamp to stream end (track it while consuming)
String text = (a > end) ? "" : stream.getText(Interval.of(a, end));

Try / catch

try { stream.getText(Interval.of(a, b)); }
catch (IllegalArgumentException e) { /* clamp b to a + available and retry, or return partial text */ }

Prevention

When it happens

Trigger: getText(Interval.of(a, b)) with b beyond the last character, e.g., a stop index computed as startIndex + expectedLength that overshoots; using a token's stop index from a different, longer input.

Common situations: Fixed-width extraction logic (read N chars starting at X) applied to short inputs; interval arithmetic reused across streams of different lengths; highlighting code that pads ranges to line ends.

Related errors


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