{"record":{"id":"eeaa8e2d511f52d0","repo":"ssssssss-team/spider-flow","slug":"start-must-be-end","errorCode":null,"errorMessage":"Start must be <= end.","messagePattern":"Start must be <= end\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/CharacterStream.java","lineNumber":20,"sourceCode":"package org.spiderflow.core.expression.parsing;\n\nimport javax.xml.transform.Source;\n\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++);","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/ssssssss-team/spider-flow/blob/c799cca99c7d064673dc79e6ef06a08bbc0e292d/spider-flow-core/src/main/java/org/spiderflow/core/expression/parsing/CharacterStream.java#L2-L38","documentation":"CharacterStream's start/end constructor validates its bounds before tokenizing an expression source. IllegalArgumentException(\"Start must be <= end.\") is thrown when the start offset is greater than the end offset, i.e. an inverted or nonsensical range.","triggerScenarios":"new CharacterStream(source, start, end) with start > end, e.g. computing a range from reversed indices or an empty slice with misplaced bounds.","commonSituations":"Custom parser extensions computing spans from variables where the start index was not yet advanced or end came from a failed match (-1 or 0).","solutions":["Check the start/end values before constructing the stream","If the range may be empty, ensure start == end (allowed), not start > end","Clamp or swap the values: end = Math.max(start, end)","Trace where the start index came from — usually a match/scan that returned a stale index"],"exampleFix":"// before\nnew CharacterStream(source, endPos, startPos);\n// after\nif (startPos > endPos) { int t = startPos; startPos = endPos; endPos = t; }\nnew CharacterStream(source, startPos, endPos);","handlingStrategy":"validation","validationCode":"if (start > end) throw new IllegalArgumentException(\"start (\" + start + \") must be <= end (\" + end + \")\");","typeGuard":null,"tryCatchPattern":"try {\n    new CharacterStream(source, start, end);\n} catch (IllegalArgumentException e) {\n    logger.error(\"Invalid stream bounds: {}..{} for len {}\", start, end, source == null ? -1 : source.length());\n}","preventionTips":["Compute start/end from a single source of truth to avoid inversion","Assert invariants (start <= end) in span-carrying data structures early","Avoid sentinel values like -1 flowing into bounds arithmetic"],"tags":["parsing","bounds-check","character-stream"],"backgroundTag":"invalid-argument-value","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"}