{"record":{"id":"3c278adcad154d91","repo":"ssssssss-team/spider-flow","slug":"end-outside-of-string","errorCode":null,"errorMessage":"End outside of string.","messagePattern":"End outside of string\\.","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/CharacterStream.java","lineNumber":23,"sourceCode":"\n/** Wraps a the content of a {@link Source} and handles traversing the contained characters. Manages a current {@link Span} via\n * the {@link #startSpan()} and {@link #endSpan()} methods. */\npublic class CharacterStream {\n\tprivate final String source;\n\tprivate int index = 0;\n\tprivate final int end;\n\n\tprivate int spanStart = 0;\n\n\tpublic CharacterStream (String source) {\n\t\tthis(source, 0, source.length());\n\t}\n\n\tpublic CharacterStream (String source, int start, int end) {\n\t\tif (start > end) throw new IllegalArgumentException(\"Start must be <= end.\");\n\t\tif (start < 0) throw new IndexOutOfBoundsException(\"Start must be >= 0.\");\n\t\tif (start > Math.max(0, source.length() - 1)) throw new IndexOutOfBoundsException(\"Start outside of string.\");\n\t\tif (end > source.length()) throw new IndexOutOfBoundsException(\"End outside of string.\");\n\n\t\tthis.source = source;\n\t\tthis.index = start;\n\t\tthis.end = end;\n\t}\n\n\t/** Returns whether there are more characters in the stream **/\n\tpublic boolean hasMore () {\n\t\treturn index < end;\n\t}\n\n\t/** Returns the next character without advancing the stream **/\n\tpublic char peek () {\n\t\tif (!hasMore()) throw new RuntimeException(\"No more characters in stream.\");\n\t\treturn source.charAt(index++);\n\t}\n\n\t/** Returns the next character and advance the stream **/","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/ssssssss-team/spider-flow/blob/c799cca99c7d064673dc79e6ef06a08bbc0e292d/spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/CharacterStream.java#L5-L41","documentation":"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().","triggerScenarios":"new CharacterStream(source, start, end) with end > source.length(), e.g. end computed as start + lookaheadWidth without clamping to the string length.","commonSituations":"Custom parsers peeking N characters ahead near end of input; arithmetic on lengths producing overshooting bounds.","solutions":["Clamp end: end = Math.min(end, source.length())","Validate the computed range before constructing the stream","Check whether a length constant (e.g. needle length) was added to an already-near-end index"],"exampleFix":"// before\nnew CharacterStream(source, start, start + MAX_TOKEN);\n// after\nint end = Math.min(start + MAX_TOKEN, source.length());\nnew CharacterStream(source, start, end);","handlingStrategy":"validation","validationCode":"if (end > source.length()) end = source.length();","typeGuard":null,"tryCatchPattern":"try {\n    new CharacterStream(source, start, end);\n} catch (IndexOutOfBoundsException e) {\n    logger.error(\"End {} exceeds source length {}\", end, source.length());\n}","preventionTips":["Clamp computed end offsets with Math.min(end, source.length())","Recompute lookahead windows near end of input","Centralize range computation in one validated helper"],"tags":["parsing","bounds-check","character-stream"],"backgroundTag":"index-out-of-bounds","analyzedSha":"c799cca99c7d064673dc79e6ef06a08bbc0e292d","analyzedAt":"2026-09-08T13:47:08.225Z","contentChangedAt":"2026-09-08T13:47:08.225Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}