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

  1. Recompute the row against the current display/block snapshot before querying
  2. Clamp the row to the snapshot maximum before calling: row = row.min(max_point().row())
  3. 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

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


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/261babad40d73cc1. Report an issue: GitHub.