ssssssss-team/spider-flow · error · RuntimeException
Reached the end of the source.
Error message
Reached the end of the source.
What it means
TokenStream.consume() advances past the current token and throws RuntimeException("Reached the end of the source.") when no token remains (hasMore() is false). Unlike next(), it is a plain RuntimeException used by parser routines (error, parseStatement, operator, parseUnaryOperator) that assume another token exists. It signals truncated or syntactically incomplete input.
Solutions
- Validate/complete the expression source before parsing (balanced operators, no trailing operators).
- Call hasMore() (or catch the RuntimeException) before/at consume() sites in custom parser extensions.
- Report a syntax error at the last token position to the user instead of surfacing the runtime exception.
- Fix the calling parser branch that consumes without checking end-of-input.
Example fix
// before
Token t = stream.consume();
// after
if (!stream.hasMore()) throw new ParseException("unexpected end of expression", stream.lastPosition());
Token t = stream.consume(); Defensive patterns
Strategy: try-catch
Validate before calling
// before running the parser, reject obviously truncated expressions
if (expr == null || expr.trim().isEmpty()) throw new IllegalArgumentException("empty expression");
if (expr.trim().matches(".*[+\-*/(<,]$")) throw new IllegalArgumentException("expression ends with a dangling operator: " + expr); Try / catch
try {
Token token = stream.consume();
} catch (RuntimeException e) {
if ("Reached the end of the source.".equals(e.getMessage())) {
throw new ParseException("Incomplete expression: expected another token", e);
}
throw e;
} Prevention
- Check stream.hasMore() before every consume() in custom parser code.
- Validate expression completeness (balanced operators/brackets) before parsing.
- Show users the source position of the last token when reporting truncation.
- Fuzz the parser with truncated inputs to find unguarded consume() call sites.
When it happens
Trigger: Calling consume() after all tokens were consumed — e.g. parsing "a +" where parseUnaryOperator/operator expects an operand token that does not exist, or parseStatement running off the end of malformed input.
Common situations: Users feeding incomplete expressions to the spider-flow expression parser (missing closing tokens/operands); template fragments cut off by truncation; grammar paths that forget to check hasMore() before consuming.
Related errors
- Start must be <= end.
- Start must be >= 0.
- Start outside of string.
- End outside of string.
- No more characters in stream.
AI-assisted analysis of ssssssss-team/spider-flow@c799cca99c (2026-09-08).
Data as JSON: /api/errors/572be46c2d662a60.
Report an issue: GitHub.
Appendix: source
Thrown at spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/TokenStream.java:39
this.end = tokens.size();
}
/** Returns whether there are more tokens in the stream. **/
public boolean hasMore () {
return index < end;
}
public boolean hasNext(){
return index + 1 < end;
}
public boolean hasPrev(){
return index > 0;
}
/** Consumes the next token and returns it. **/
public Token consume () {
if (!hasMore()) throw new RuntimeException("Reached the end of the source.");
return tokens.get(index++);
}
public Token next(){
if (!hasMore()) throw new RuntimeException("Reached the end of the source.");
return tokens.get(++index);
}
public Token prev(){
if(index == 0){
throw new RuntimeException("Reached the end of the source.");
}
return tokens.get(--index);
}
/** Checks if the next token has the give type and optionally consumes, or throws an error if the next token did not match the
* type. */
public Token expect (TokenType type) {View on GitHub (pinned to c799cca99c)