zed-industries/zed · error
row out of range
Error message
row out of range
What it means
BlockMapSnapshot::line_len(BlockRow) seeks the transform tree to find the wrap row for a given block row. If the seek finds no transform (the row lies past the end of the map) and the row is not row 0 of an empty map, the method panics 'row out of range'. It is an internal bounds invariant of the editor's display map: block rows must be within the snapshot's row range.
Source
Thrown at crates/editor/src/display_map/block_map.rs:2473
}
#[ztracing::instrument(skip_all)]
pub(super) fn line_len(&self, row: BlockRow) -> u32 {
let (start, _, item) =
self.transforms
.find::<Dimensions<BlockRow, WrapRow>, _>((), &row, Bias::Right);
if let Some(transform) = item {
let Dimensions(output_start, input_start, _) = start;
let overshoot = row - output_start;
if transform.block.is_some() {
0
} else {
self.wrap_snapshot.line_len(input_start + overshoot)
}
} else if row == BlockRow(0) {
0
} else {
panic!("row out of range");
}
}
#[ztracing::instrument(skip_all)]
pub(super) fn is_block_line(&self, row: BlockRow) -> bool {
let (_, _, item) = self.transforms.find::<BlockRow, _>((), &row, Bias::Right);
item.is_some_and(|t| t.block.is_some())
}
#[ztracing::instrument(skip_all)]
pub(super) fn is_folded_buffer_header(&self, row: BlockRow) -> bool {
let (_, _, item) = self.transforms.find::<BlockRow, _>((), &row, Bias::Right);
let Some(transform) = item else {
return false;
};
matches!(transform.block, Some(Block::FoldedBuffer { .. }))
}
View on GitHub (pinned to f4178619ac)
Solutions
- Recompute the row against the current display/block snapshot before querying
- Clamp the row to the snapshot maximum before calling: row = row.min(max_point().row())
- If it reproduces with plain Zed usage, capture repro steps and report it — this is an internal invariant violation, not caller-configurable behavior
Example fix
// before let len = block_snapshot.line_len(row); // row may be stale/out of range // after let max_row = block_snapshot.max_point().row(); let len = block_snapshot.line_len(row.min(max_row));
Defensive patterns
Strategy: validation
Validate before calling
let max_row = block_snapshot.max_point().row(); let row = row.min(max_row); let len = block_snapshot.line_len(row);
Type guard
fn block_row_in_range(snapshot: &BlockMapSnapshot, row: BlockRow) -> bool {
row <= snapshot.max_point().row()
} Prevention
- Never reuse rows across snapshots; recompute from the snapshot you query
- Clamp externally derived rows to max_point() before display-map lookups
- In editor code, treat this panic as a bug report: attach repro steps
When it happens
Trigger: Querying line_len with a BlockRow that is >= the snapshot's row count — usually a row computed against an older DisplaySnapshot after edits/blocks changed, or an off-by-one where row_count is passed instead of the last valid row.
Common situations: Editor code paths using stale rows after a concurrent edit; plugin or new feature code reusing rows across snapshot versions; regressions in display_map internals.
Related errors
- invalid display row {}
- blocking sender returned without value
- anchor's path was never added to multibuffer
- byte index {} is out of bounds of rope (length: {})
- {self:?} is not a named SearchOption
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/261babad40d73cc1.
Report an issue: GitHub.