{"record":{"id":"1cd64674aa84b670","repo":"ssssssss-team/spider-flow","slug":"start-must-be-0-1cd646","errorCode":null,"errorMessage":"Start must be >= 0.","messagePattern":"Start must be >= 0\\.","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/Span.java","lineNumber":24,"sourceCode":"\t/** the source string this span refers to **/\n\tprivate final String source;\n\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;","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/ssssssss-team/spider-flow/blob/c799cca99c7d064673dc79e6ef06a08bbc0e292d/spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/Span.java#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before\nint idx = source.indexOf('=');\nSpan span = new Span(source, idx, source.length());\n// after\nint idx = source.indexOf('=');\nif (idx < 0) throw new IllegalArgumentException(\"'=' not found in source\");\nSpan span = new Span(source, idx, source.length());","handlingStrategy":"validation","validationCode":"if (source == null) throw new IllegalArgumentException(\"source is null\");\nif (start < 0 || start > end || end > source.length()) throw new IllegalArgumentException(\"invalid span range [\" + start + \",\" + end + \"] for source of length \" + source.length());","typeGuard":"boolean isValidSpan(String source, int start, int end) {\n    return source != null && start >= 0 && start <= end && end <= source.length() && start < source.length();\n}","tryCatchPattern":"try {\n    Span span = new Span(source, start, end);\n} catch (IndexOutOfBoundsException | IllegalArgumentException e) {\n    // log start/end/source.length() and fall back to a full-source span\n    Span span = new Span(source);\n}","preventionTips":["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."],"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-16T09:17:16.951Z"}