zed-industries/zed · error

invalid display row {}

Error message

invalid display row {}

What it means

FoldMapSnapshot::row_infos(start_row) iterates fold rows starting at a display row; it panics with 'invalid display row {}' when start_row exceeds the snapshot's total row count (transforms summary output lines). Note the check is `>`, so start_row equal to the row count is legal (empty iterator at the end); anything beyond is invalid.

Source

Thrown at crates/editor/src/display_map/fold_map.rs:829

    pub fn len(&self) -> FoldOffset {
        FoldOffset(self.transforms.summary().output.len)
    }

    #[ztracing::instrument(skip_all)]
    pub fn line_len(&self, row: u32) -> u32 {
        let line_start = FoldPoint::new(row, 0).to_offset(self).0;
        let line_end = if row >= self.max_point().row() {
            self.len().0
        } else {
            FoldPoint::new(row + 1, 0).to_offset(self).0 - 1
        };
        (line_end - line_start) as u32
    }

    #[ztracing::instrument(skip_all)]
    pub fn row_infos(&self, start_row: u32) -> FoldRows<'_> {
        if start_row > self.transforms.summary().output.lines.row {
            panic!("invalid display row {}", start_row);
        }

        let fold_point = FoldPoint::new(start_row, 0);
        let mut cursor = self
            .transforms
            .cursor::<Dimensions<FoldPoint, InlayPoint>>(());
        cursor.seek(&fold_point, Bias::Left);

        let overshoot = fold_point.0 - cursor.start().0.0;
        let inlay_point = InlayPoint(cursor.start().1.0 + overshoot);
        let input_rows = self.inlay_snapshot.row_infos(inlay_point.row());

        FoldRows {
            fold_point,
            input_rows,
            cursor,
        }
    }

View on GitHub (pinned to f4178619ac)

Solutions

  1. Derive start_row from the same snapshot you call row_infos on
  2. Clamp before calling: start_row = start_row.min(snapshot.max_point().row())
  3. If triggered inside Zed with no custom code, report the panic with the document/edit history — it indicates an internal invariant break

Example fix

// before
let infos = fold_snapshot.row_infos(start_row); // possibly > row count

// after
let max_row = fold_snapshot.max_point().row();
let infos = fold_snapshot.row_infos(start_row.min(max_row));
Defensive patterns

Strategy: validation

Validate before calling

let max_row = fold_snapshot.max_point().row();
let start = start_row.min(max_row + 1); // row == count is allowed (empty tail)
let infos = fold_snapshot.row_infos(start);

Type guard

fn fold_row_in_range(snapshot: &FoldSnapshot, row: u32) -> bool {
    row <= snapshot.transforms_row_count() // i.e. summary().output.lines.row
}

Prevention

When it happens

Trigger: Calling row_infos (or editor APIs that delegate to it, like display_map row iteration) with a start row greater than the number of display rows — e.g. a row taken from a stale FoldSnapshot after folds or edits changed, or an unclamped loop bound from another snapshot.

Common situations: Rows cached from an earlier render pass reused after document edits; multi-snapshot code mixing buffer rows with display rows; internal regressions after fold changes.

Related errors


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