iced-rs/iced · error

Line layout should be cached

Error message

Line layout should be cached

What it means

cosmic-text computes line layouts lazily: a BufferLine only carries a layout after shaping ran (shape_until_scroll / shape_as_needed, invoked from Editor::update/overwrite/perform). Editor::highlight (editor.rs:821) walks the visible window line by line and asserts line.layout_opt() is Some; if any line in [scroll.line, last_visible_line] was never shaped, expect("Line layout should be cached") fires.

Solutions

  1. Run the editor lifecycle in order: with_text/update (which shapes) before highlight, mirroring iced's text_editor widget
  2. Pass identical bounds to update and the subsequent highlight so the visible window matches what was shaped
  3. For very large buffers, ensure shaping completed past the visible region before highlighting
  4. If it persists with stock widgets, upgrade iced: visible-window/shaping order bugs were fixed across releases

Example fix

// before - highlight before any shaping ran
let mut editor = Editor::with_text(text);
editor.highlight(font, &mut highlighter, fmt);

// after - shape first, then highlight
editor.update(bounds, font, size, line_height, wrapping, alignment, hint_factor, &mut highlighter);
editor.highlight(font, &mut highlighter, fmt);
Defensive patterns

Strategy: validation

Validate before calling

// before triggering highlight, confirm the visible lines are shaped
let shaped = editor.buffer().lines.iter().all(|l| l.layout_opt().is_some());
if !shaped {
    // run the update/shaping pass first (correct bounds, font, size)
    editor.update(bounds, font, size, line_height, wrapping, alignment, hint, &mut highlighter);
}
editor.highlight(font, &mut highlighter, fmt);

Prevention

When it happens

Trigger: Calling highlight before any shaping pass ran; passing bounds to update that are smaller than what highlight later assumes, so the visible window reaches unshaped lines; scrolling deep into a huge document whose shaping was cut short (shape_until_scroll with false).

Common situations: Custom widgets driving editor::Editor with a hand-ordered lifecycle (highlight before update); resizing the editor between update and highlight; loading very large files where shaping has not caught up with the scroll position.

Related errors


AI-assisted analysis of iced-rs/iced@3de451447b (2026-08-17). Data as JSON: /api/errors/90b0ae120b7f3ab5. Report an issue: GitHub.

Appendix: source

Thrown at graphics/src/text/editor.rs:821

        highlighter: &mut H,
        format_highlight: impl Fn(&H::Highlight) -> highlighter::Format<Self::Font>,
    ) {
        let internal = self.internal();
        let buffer = buffer_from_editor(&internal.editor);

        let scroll = buffer.scroll();
        let mut window = (internal.bounds.height * internal.hint_factor
            / buffer.metrics().line_height)
            .ceil() as i32;

        let last_visible_line = buffer.lines[scroll.line..]
            .iter()
            .enumerate()
            .find_map(|(i, line)| {
                let visible_lines = line
                    .layout_opt()
                    .as_ref()
                    .expect("Line layout should be cached")
                    .len() as i32;

                if window > visible_lines {
                    window -= visible_lines;
                    None
                } else {
                    Some(scroll.line + i)
                }
            })
            .unwrap_or(buffer.lines.len().saturating_sub(1));

        let current_line = highlighter.current_line();

        if current_line > last_visible_line {
            return;
        }

        let editor = self.0.take().expect("Editor should always be initialized");

View on GitHub (pinned to 3de451447b)