ssssssss-team/spider-flow · error · IndexOutOfBoundsException
Start must be >= 0.
Error message
Start must be >= 0.
What it means
The Span(String,int,int) constructor validates that the start offset is non-negative and throws IndexOutOfBoundsException("Start must be >= 0.") when a negative start is passed. Spans mark a character range inside a source string, so a negative start is meaningless. This is a fail-fast guard against programmer error in the caller.
Solutions
- Check the start offset before constructing: ensure start >= 0.
- Fix the offset computation that produced a negative value (e.g. an indexOf that returned -1).
- Clamp negative offsets to 0 if that is semantically valid for the caller.
- Use the single-argument Span(source) constructor when the span should cover the whole source.
Example fix
// before
int idx = source.indexOf('=');
Span span = new Span(source, idx, source.length());
// after
int idx = source.indexOf('=');
if (idx < 0) throw new IllegalArgumentException("'=' not found in source");
Span span = new Span(source, idx, source.length()); Defensive patterns
Strategy: validation
Validate before calling
if (source == null) throw new IllegalArgumentException("source is null");
if (start < 0 || start > end || end > source.length()) throw new IllegalArgumentException("invalid span range [" + start + "," + end + "] for source of length " + source.length()); Type guard
boolean isValidSpan(String source, int start, int end) {
return source != null && start >= 0 && start <= end && end <= source.length() && start < source.length();
} Try / catch
try {
Span span = new Span(source, start, end);
} catch (IndexOutOfBoundsException | IllegalArgumentException e) {
// log start/end/source.length() and fall back to a full-source span
Span span = new Span(source);
} Prevention
- Never use -1 as a span offset; check indexOf-style results before use.
- Assert start >= 0 and start <= end in offset-computation helpers.
- Prefer deriving spans from Token objects rather than raw arithmetic.
- Unit-test span construction with empty and single-character sources.
When it happens
Trigger: Calling new Span(source, start, end) with a start value below 0, e.g. a computed offset that went negative due to subtraction on an empty or short string.
Common situations: Off-by-one arithmetic when slicing expressions, passing -1 as a default sentinel start, or computing substring offsets with charAt/indexOf results that returned -1 (not found).
Related errors
- Start outside of string.
- End outside of string.
- Start must be >= 0.
- Start must be <= end.
- The two spans do not reference the same source.
AI-assisted analysis of ssssssss-team/spider-flow@c799cca99c (2026-09-08).
Data as JSON: /api/errors/1cd64674aa84b670.
Report an issue: GitHub.
Appendix: source
Thrown at spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/Span.java:24
/** the source string this span refers to **/
private final String source;
/** start index in source string, starting at 0 **/
private int start;
/** end index in source string, exclusive, starting at 0 **/
private int end;
/** Cached String instance to reduce pressure on GC **/
private final String cachedText;
public Span (String source) {
this(source, 0, source.length());
}
public Span (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 > 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.start = start;
this.end = end;
this.cachedText = source.substring(start, end);
}
public Span (Span start, Span end) {
if (!start.source.equals(end.source)) throw new IllegalArgumentException("The two spans do not reference the same source.");
if (start.start > end.end) throw new IllegalArgumentException("Start must be <= end.");
if (start.start < 0) throw new IndexOutOfBoundsException("Start must be >= 0.");
if (start.start > start.source.length() - 1) throw new IndexOutOfBoundsException("Start outside of string.");
if (end.end > start.source.length()) throw new IndexOutOfBoundsException("End outside of string.");
this.source = start.source;View on GitHub (pinned to c799cca99c)