jhy/jsoup · error · IllegalArgumentException
Source ranges must come from the same parse
Error message
Source ranges must come from the same parse
What it means
Internal consistency guard in Range.useLineMap: the parser attached ranges whose position data derives from more than one Document/parse. jsoup tracks character positions per parse via a single line map; once the first range's line map is retained, any subsequent range created from a different parse cannot be translated to line/column correctly. This fires when ranges from separately parsed documents (or manually fabricated Position/range data not tied to the current parse) are mixed on the same node or attribute set.
Solutions
- Ensure all nodes and attribute ranges come from a single Document.parse call; do not merge nodes across separately parsed documents before reading source ranges.
- If combining content from multiple parses, read each document's ranges before merging, or re-parse the combined input so all ranges share one line map.
- Avoid constructing Range/Position values manually unless they originate from the same parser instance's line map.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/main/java/org/jsoup/nodes/Range.java:437 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of jhy/jsoup@9851ac5d9c (2026-09-08).
Data as JSON: /api/errors/32af2c35711cf4b0.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/org/jsoup/nodes/Range.java:437
throw new IllegalArgumentException("Attribute range positions must be non-negative");
useLineMap(lineMap);
int nameIndex = attrNameStartIndex(index);
int valueIndex = attrValueStartIndex(index);
ensureAttributeCapacity(valueIndex + 2);
attrRanges[nameIndex] = nameStart;
attrRanges[nameIndex + 1] = nameEnd;
attrRanges[valueIndex] = valueStart;
attrRanges[valueIndex + 1] = valueEnd;
}
/**
Retains the first line map and rejects mixed-source ranges.
*/
private void useLineMap(LineMap lineMap) {
if (this.lineMap == UnsetLineMap) {
this.lineMap = lineMap;
} else if (this.lineMap != lineMap) {
throw new IllegalArgumentException("Source ranges must come from the same parse");
}
}
/**
Removes an attribute slot and shifts following source ranges.
*/
void removeAttributeRange(int index) {
if (index < 0) return;
int[] ranges = attrRanges;
int removeIndex = attrNameStartIndex(index);
if (removeIndex >= ranges.length) return;
int nextIndex = removeIndex + AttrRangeWidth;
int shifted = ranges.length - nextIndex;
if (shifted > 0)
System.arraycopy(ranges, nextIndex, ranges, removeIndex, shifted);
Arrays.fill(ranges, ranges.length - AttrRangeWidth, ranges.length, -1);
}View on GitHub (pinned to 9851ac5d9c)