ssssssss-team/spider-flow · error · IndexOutOfBoundsException

End outside of string.

Error message

End outside of string.

What it means

CharacterStream's constructor validates that the end offset does not exceed the source string length, throwing IndexOutOfBoundsException("End outside of string."). The end is exclusive but must be <= source.length().

Solutions

  1. Clamp end: end = Math.min(end, source.length())
  2. Validate the computed range before constructing the stream
  3. Check whether a length constant (e.g. needle length) was added to an already-near-end index

Example fix

// before
new CharacterStream(source, start, start + MAX_TOKEN);
// after
int end = Math.min(start + MAX_TOKEN, source.length());
new CharacterStream(source, start, end);
Defensive patterns

Strategy: validation

Validate before calling

if (end > source.length()) end = source.length();

Try / catch

try {
    new CharacterStream(source, start, end);
} catch (IndexOutOfBoundsException e) {
    logger.error("End {} exceeds source length {}", end, source.length());
}

Prevention

When it happens

Trigger: new CharacterStream(source, start, end) with end > source.length(), e.g. end computed as start + lookaheadWidth without clamping to the string length.

Common situations: Custom parsers peeking N characters ahead near end of input; arithmetic on lengths producing overshooting bounds.

Related errors


AI-assisted analysis of ssssssss-team/spider-flow@c799cca99c (2026-09-08). Data as JSON: /api/errors/3c278adcad154d91. Report an issue: GitHub.

Appendix: source

Thrown at spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/CharacterStream.java:23

/** Wraps a the content of a {@link Source} and handles traversing the contained characters. Manages a current {@link Span} via
 * the {@link #startSpan()} and {@link #endSpan()} methods. */
public class CharacterStream {
	private final String source;
	private int index = 0;
	private final int end;

	private int spanStart = 0;

	public CharacterStream (String source) {
		this(source, 0, source.length());
	}

	public CharacterStream (String source, int start, int end) {
		if (start > end) throw new IllegalArgumentException("Start must be <= end.");
		if (start < 0) throw new IndexOutOfBoundsException("Start must be >= 0.");
		if (start > Math.max(0, source.length() - 1)) throw new IndexOutOfBoundsException("Start outside of string.");
		if (end > source.length()) throw new IndexOutOfBoundsException("End outside of string.");

		this.source = source;
		this.index = start;
		this.end = end;
	}

	/** Returns whether there are more characters in the stream **/
	public boolean hasMore () {
		return index < end;
	}

	/** Returns the next character without advancing the stream **/
	public char peek () {
		if (!hasMore()) throw new RuntimeException("No more characters in stream.");
		return source.charAt(index++);
	}

	/** Returns the next character and advance the stream **/

View on GitHub (pinned to c799cca99c)