{"record":{"id":"b35afbd9af5fcb21","repo":"ssssssss-team/spider-flow","slug":"start-outside-of-string-b35afb","errorCode":null,"errorMessage":"Start outside of string.","messagePattern":"Start outside of string\\.","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/Span.java","lineNumber":26,"sourceCode":"\n\t/** start index in source string, starting at 0 **/\n\tprivate int start;\n\n\t/** end index in source string, exclusive, starting at 0 **/\n\tprivate int end;\n\n\t/** Cached String instance to reduce pressure on GC **/\n\tprivate final String cachedText;\n\n\tpublic Span (String source) {\n\t\tthis(source, 0, source.length());\n\t}\n\n\tpublic Span (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 > source.length() - 1) \n\t\t\tthrow 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.start = start;\n\t\tthis.end = end;\n\t\tthis.cachedText = source.substring(start, end);\n\t}\n\n\tpublic Span (Span start, Span end) {\n\t\tif (!start.source.equals(end.source)) throw new IllegalArgumentException(\"The two spans do not reference the same source.\");\n\t\tif (start.start > end.end) throw new IllegalArgumentException(\"Start must be <= end.\");\n\t\tif (start.start < 0) throw new IndexOutOfBoundsException(\"Start must be >= 0.\");\n\t\tif (start.start > start.source.length() - 1) throw new IndexOutOfBoundsException(\"Start outside of string.\");\n\t\tif (end.end > start.source.length()) throw new IndexOutOfBoundsException(\"End outside of string.\");\n\n\t\tthis.source = start.source;\n\t\tthis.start = start.start;\n\t\tthis.end = end.end;","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/ssssssss-team/spider-flow/blob/c799cca99c7d064673dc79e6ef06a08bbc0e292d/spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/Span.java#L8-L44","documentation":"The Span(String,int,int) constructor throws IndexOutOfBoundsException(\"Start outside of string.\") when start is greater than source.length() - 1, i.e. the start offset points past the last character. The span must begin within the source text. Note this also rejects start == source.length(), so a zero-length span at the end of the source is not allowed by this constructor.","triggerScenarios":"Calling new Span(source, start, end) where start >= source.length(), e.g. start == source.length() for an empty range at end-of-input, or an empty source string with start=0.","commonSituations":"Tokenizing to end of input and building an EOF span at offset source.length(); constructing spans over empty strings; parser code that carries a cursor past the last character.","solutions":["Ensure start <= source.length() - 1 and that the source is non-empty before constructing.","For an EOF/end-of-input marker, build the span with end <= source.length() and start < source.length(), or add a guard for empty input.","Handle the empty-source case explicitly before creating spans.","Use the single-argument Span(source) constructor when the span covers the entire source."],"exampleFix":"// before\nSpan eof = new Span(source, source.length(), source.length());\n// after\nSpan eof = source.isEmpty() ? null : new Span(source, Math.min(source.length() - 1, start), source.length());","handlingStrategy":"validation","validationCode":"if (source == null || source.isEmpty()) throw new IllegalArgumentException(\"source must be non-empty\");\nif (start >= source.length()) throw new IllegalArgumentException(\"start \" + start + \" outside source of length \" + source.length());","typeGuard":"boolean canStartSpan(String source, int start) {\n    return source != null && !source.isEmpty() && start >= 0 && start < source.length();\n}","tryCatchPattern":"try {\n    Span span = new Span(source, start, end);\n} catch (IndexOutOfBoundsException e) {\n    // clamp start for EOF-style spans\n    Span span = new Span(source, Math.max(0, source.length() - 1), source.length());\n}","preventionTips":["Remember this constructor forbids start == source.length(): no zero-length span at the very end.","Model EOF positions with start = source.length() - 1, end = source.length().","Guard empty-input parsing before building any spans.","Clamp cursor positions with Math.min(pos, source.length() - 1)."],"tags":["parsing","index-out-of-bounds","span"],"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-16T04:17:20.429Z"}