sinelaw/fresh · error
Invalid range: start offset
Error message
Invalid range: start offset {} > end offset {} What it means
get_range resolved both DocumentPosition endpoints to byte offsets and found start_offset > end_offset, so the requested range is inverted. state.rs:2075 bails because slicing a buffer backwards is meaningless. The caller must order the positions correctly.
Solutions
- Order the two positions before the call (min/max on offsets)
- If using a selection, sort anchor and cursor so start <= end
- Verify the DocumentPosition values were not accidentally swapped at the call site
Example fix
// before
let text = doc.get_range(sel.cursor, sel.anchor)?;
// after
let (s, e) = if sel.cursor <= sel.anchor { (sel.cursor, sel.anchor) } else { (sel.anchor, sel.cursor) };
let text = doc.get_range(s, e)?; Defensive patterns
Strategy: validation
Validate before calling
let (s, e) = (doc.position_to_offset(&start)?, doc.position_to_offset(&end)?);
assert!(s <= e, "range start {} after end {}", s, e); Try / catch
match doc.get_range(start, end) {
Err(e) if e.to_string().contains("Invalid range: start offset") => normalize_and_retry(start, end),
other => other,
} Prevention
- Always normalize selection anchor/cursor to (min, max) before range reads
- Add an assertion for start <= end at range-producing call sites
- Centralize range construction in one helper that orders offsets
When it happens
Trigger: Calling get_range with a start position that comes after the end position in the document — e.g. swapping selection anchors, or passing cursor/anchor in the wrong order.
Common situations: Selection code where the user dragged backwards (anchor after cursor); programmatic edits passing unordered offsets; LSP range conversion done in the wrong direction.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Line indexing not available for this document
- Buffer range out of bounds: requested
- Buffer has unsaved changes
- no split layout
- Buffer has no file path
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/11bb58a1c6f4cabc.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/state.rs:2075
DocumentPosition::LineColumn {
line: pos.line,
column: pos.column,
}
} else {
// Line index exists but metadata unavailable - fall back to byte offset
DocumentPosition::ByteOffset(offset)
}
} else {
DocumentPosition::ByteOffset(offset)
}
}
fn get_range(&mut self, start: DocumentPosition, end: DocumentPosition) -> Result<String> {
let start_offset = self.position_to_offset(start)?;
let end_offset = self.position_to_offset(end)?;
if start_offset > end_offset {
anyhow::bail!(
"Invalid range: start offset {} > end offset {}",
start_offset,
end_offset
);
}
let bytes = self
.buffer
.get_text_range_mut(start_offset, end_offset - start_offset)?;
Ok(String::from_utf8_lossy(&bytes).into_owned())
}
fn get_line_content(&mut self, line_number: usize) -> Option<String> {
if !self.has_line_index() {
return None;
}
View on GitHub (pinned to 67894ca546)