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
- Wrap the printing sink in WithSyntaxHighlighting on the offending path before lines are produced
- If highlighting is intentionally unavailable there, render the plain line text instead of expecting cached spans
- 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
- Wrap every details-printing sink in WithSyntaxHighlighting at construction time, not selectively
- When adding output formats, route them through the same highlighter setup as human output
- Degrade to plain text (let-else + continue) instead of expecting cached highlights
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
- target OID must exist when ahead calculation is enabled
- target OID must exist when merge check is enabled
- classified branches are guaranteed to be non-empty
- committed files being non-empty means paths are non-empty
- changes being non-empty means paths are non-empty
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/00458f5c69455b0a.
Report an issue: GitHub.