gitbutlerapp/gitbutler · error

WithSyntaxHighlighting ensures the line is highlighted

Error message

WithSyntaxHighlighting ensures the line is highlighted

What it means

Rendering invariant panic in the diff-details printer: a DetailsLine::Code line is being printed, but its syntax_highlighted_line RefCell is still None. Code lines get their highlighted spans pre-computed only when the details sink runs wrapped in WithSyntaxHighlighting, which fills the cache during iteration; printing Code lines through a path that skipped that wrapper trips the expect.

Source

Thrown at crates/but/src/command/legacy/diff2.rs:360

impl DiffLineWriter for DiffWriter<'_> {
    fn write(&mut self, line: DetailsLine) -> anyhow::Result<()> {
        match line {
            DetailsLine::Text { line, .. } => {
                let line_style = line.style;
                for span in line.spans {
                    let rendered = line_style.patch(span.style).paint(&span.content);
                    write!(self.out, "{rendered}")?;
                }
                writeln!(self.out)?;
            }
            DetailsLine::TextToWrap { id: _, text } => {
                writeln!(self.out, "{text}")?;
            }
            DetailsLine::Code(code_line) => {
                let syntax_highlighted_line = code_line.syntax_highlighted_line.borrow();
                let syntax_highlighted_line = syntax_highlighted_line
                    .as_ref()
                    .expect("WithSyntaxHighlighting ensures the line is highlighted");

                let line_style = syntax_highlighted_line.style;
                for span in syntax_highlighted_line {
                    let rendered = line_style.patch(span.style).paint(&span.content);
                    write!(self.out, "{rendered}")?;
                }
                if line_style.bg.is_some() && colored::control::SHOULD_COLORIZE.should_colorize() {
                    write!(self.out, "{}", line_style.paint(CLEAR_TO_END_OF_LINE))?;
                }
                writeln!(self.out)?;
            }
            DetailsLine::SectionSeparator => {
                writeln!(self.out)?;
            }
            DetailsLine::HunkHeader { width, line, .. } => {
                for _ in 0..width {
                    write!(self.out, "{}", self.theme.border.paint("─"))?;
                }

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Wrap the printing sink in WithSyntaxHighlighting on the offending path before lines are produced
  2. If highlighting is intentionally unavailable there, render the plain line text instead of expecting cached spans
  3. File an issue with the exact 'but diff ...' invocation - the invariant must hold for all public flag combinations

Example fix

// before
let syntax_highlighted_line = syntax_highlighted_line.as_ref()
    .expect("WithSyntaxHighlighting ensures the line is highlighted");

// after - degrade to plain text instead of panicking
let Some(hl) = code_line.syntax_highlighted_line.borrow().as_ref() else {
    writeln!(self.out, "{}", code_line.content)?; // field per DetailsLine::Code
    continue;
};
Defensive patterns

Strategy: validation

Validate before calling

// Renderer-side invariant test: every Code line must be pre-highlighted before print
fn assert_all_code_lines_highlighted(lines: &[DetailsLine]) {
    for line in lines {
        if let DetailsLine::Code(c) = line {
            assert!(c.syntax_highlighted_line.borrow().is_some(), "Code line never highlighted");
        }
    }
}

Prevention

When it happens

Trigger: A code path constructs the details renderer without the WithSyntaxHighlighting wrapper yet still emits DetailsLine::Code; a refactor moves highlighting from construction time to render time for some formats only; a feature-gated highlighter is compiled out while Code lines still render.

Common situations: Refactors of the diff rendering pipeline; machine-readable formats accidentally routed through the human renderer; new details line kinds added without extending the highlighting pass.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/00458f5c69455b0a. Report an issue: GitHub.