zed-industries/zed · error
byte index {} is out of bounds of `{:?}` (length: {})
Error message
byte index {} is out of bounds of `{:?}` (length: {}) What it means
The rope crate stores text in chunks and mirrors Rust's string-slicing panics: when a byte offset exceeds the text's byte length, panic_char_boundary reports 'byte index ... is out of bounds (length: N)'. It is the rope equivalent of &s[i..] with i > s.len(), and almost always means an offset computed against one version of the text was applied to a shorter one.
Source
Thrown at crates/rope/src/chunk.rs:739
#[inline(always)]
fn nth_set_bit(v: u128, n: usize) -> usize {
let low = v as u64;
let high = (v >> 64) as u64;
let low_count = low.count_ones() as usize;
if n > low_count {
64 + nth_set_bit_u64(high, (n - low_count) as u64) as usize
} else {
nth_set_bit_u64(low, n as u64) as usize
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn panic_char_boundary(text: &str, offset: usize) -> ! {
if offset > text.len() {
panic!(
"byte index {} is out of bounds of `{:?}` (length: {})",
offset,
text,
text.len()
);
}
// find the character
let char_start = text.floor_char_boundary(offset);
// `char_start` must be less than len and a char boundary
let ch = text.get(char_start..).unwrap().chars().next().unwrap();
let char_range = char_start..char_start + ch.len_utf8();
panic!(
"byte index {} is not a char boundary; it is inside {:?} (bytes {:?})",
offset, ch, char_range,
);
}
#[cold]View on GitHub (pinned to f4178619ac)
Solutions
- Recompute offsets from the current snapshot (to_offset on the up-to-date text) instead of reusing cached values
- Clamp before use: offset.min(text.len()) - and remember offset == len is valid as an exclusive end
- When walking forward n bytes, stop the walk at the end of the rope/chunk
- Add debug_assert!(offset <= len) at the boundary where offsets enter your code
Example fix
// before let next = cached_offset + 8; let slice = rope.byte_slice(next..); // panics when next > rope.len() // after let next = (cached_offset + 8).min(rope.len()); let slice = rope.byte_slice(next..);
Defensive patterns
Strategy: validation
Validate before calling
fn clamp_offset(offset: usize, len: usize) -> usize {
offset.min(len)
}
let len = snapshot.len();
let start = clamp_offset(start, len);
let end = clamp_offset(end.max(start), len); Prevention
- Never cache byte offsets across edits; recompute them from the live snapshot
- Clamp at every arithmetic site: offset + n can exceed len
- Fuzz with property tests asserting offsets stay within 0..=len
- Prefer Point- or Anchor-based APIs over raw byte arithmetic
When it happens
Trigger: Calling rope chunk APIs that validate byte offsets (char/byte iteration, slicing, summary lookups in crates/rope/src/chunk.rs) with an offset greater than the chunk length: stale offsets reused after edits, off-by-one at range ends (offset == len is a valid exclusive end, len + 1 is not), or arithmetic that walks past the end.
Common situations: Caching byte offsets across edits and reusing them; computing offset + n without clamping; mixing point/offset conversions from different snapshots; fuzz tests generating unclamped offsets.
Related errors
- byte index {} is not a char boundary; it is inside {:?} (byt
- byte index {} is out of bounds of rope (length: {})
- unsupported TOML value in .env.toml for key {}
- database not initialized
- actions.json not found at {}: {}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/06bd552ada9558e6.
Report an issue: GitHub.