ssssssss-team/spider-flow · error · IllegalArgumentException

Start must be <= end.

Error message

Start must be <= end.

What it means

CharacterStream's start/end constructor validates its bounds before tokenizing an expression source. IllegalArgumentException("Start must be <= end.") is thrown when the start offset is greater than the end offset, i.e. an inverted or nonsensical range.

Solutions

  1. Check the start/end values before constructing the stream
  2. If the range may be empty, ensure start == end (allowed), not start > end
  3. Clamp or swap the values: end = Math.max(start, end)
  4. Trace where the start index came from — usually a match/scan that returned a stale index

Example fix

// before
new CharacterStream(source, endPos, startPos);
// after
if (startPos > endPos) { int t = startPos; startPos = endPos; endPos = t; }
new CharacterStream(source, startPos, endPos);
Defensive patterns

Strategy: validation

Validate before calling

if (start > end) throw new IllegalArgumentException("start (" + start + ") must be <= end (" + end + ")");

Try / catch

try {
    new CharacterStream(source, start, end);
} catch (IllegalArgumentException e) {
    logger.error("Invalid stream bounds: {}..{} for len {}", start, end, source == null ? -1 : source.length());
}

Prevention

When it happens

Trigger: new CharacterStream(source, start, end) with start > end, e.g. computing a range from reversed indices or an empty slice with misplaced bounds.

Common situations: Custom parser extensions computing spans from variables where the start index was not yet advanced or end came from a failed match (-1 or 0).

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

package org.spiderflow.core.expression.parsing;

import javax.xml.transform.Source;

/** 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++);

View on GitHub (pinned to c799cca99c)