{"record":{"id":"572be46c2d662a60","repo":"ssssssss-team/spider-flow","slug":"reached-the-end-of-the-source","errorCode":null,"errorMessage":"Reached the end of the source.","messagePattern":"Reached the end of the source\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/TokenStream.java","lineNumber":39,"sourceCode":"\t\tthis.end = tokens.size();\n\t}\n\n\t/** Returns whether there are more tokens in the stream. **/\n\tpublic boolean hasMore () {\n\t\treturn index < end;\n\t}\n\t\n\tpublic boolean hasNext(){\n\t\treturn index + 1 < end;\n\t}\n\t\n\tpublic boolean hasPrev(){\n\t\treturn index > 0;\n\t}\n\n\t/** Consumes the next token and returns it. **/\n\tpublic Token consume () {\n\t\tif (!hasMore()) throw new RuntimeException(\"Reached the end of the source.\");\n\t\treturn tokens.get(index++);\n\t}\n\t\n\tpublic Token next(){\n\t\tif (!hasMore()) throw new RuntimeException(\"Reached the end of the source.\");\n\t\treturn tokens.get(++index);\n\t}\n\t\n\tpublic Token prev(){\n\t\tif(index == 0){\n\t\t\tthrow new RuntimeException(\"Reached the end of the source.\");\n\t\t}\n\t\treturn tokens.get(--index);\n\t}\n\n\t/** Checks if the next token has the give type and optionally consumes, or throws an error if the next token did not match the\n\t * type. */\n\tpublic Token expect (TokenType type) {","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/ssssssss-team/spider-flow/blob/c799cca99c7d064673dc79e6ef06a08bbc0e292d/spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/TokenStream.java#L21-L57","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nToken t = stream.consume();\n// after\nif (!stream.hasMore()) throw new ParseException(\"unexpected end of expression\", stream.lastPosition());\nToken t = stream.consume();","handlingStrategy":"try-catch","validationCode":"// before running the parser, reject obviously truncated expressions\nif (expr == null || expr.trim().isEmpty()) throw new IllegalArgumentException(\"empty expression\");\nif (expr.trim().matches(\".*[+\\-*/(<,]$\")) throw new IllegalArgumentException(\"expression ends with a dangling operator: \" + expr);","typeGuard":null,"tryCatchPattern":"try {\n    Token token = stream.consume();\n} catch (RuntimeException e) {\n    if (\"Reached the end of the source.\".equals(e.getMessage())) {\n        throw new ParseException(\"Incomplete expression: expected another token\", e);\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["parsing","token-stream","syntax-error"],"backgroundTag":"unexpected-end-of-input","analyzedSha":"c799cca99c7d064673dc79e6ef06a08bbc0e292d","analyzedAt":"2026-09-08T13:47:08.225Z","contentChangedAt":"2026-09-08T13:47:08.225Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}