gitbutlerapp/gitbutler · error
line should have been highlighted by now
Error message
line should have been highlighted by now
What it means
Internal invariant panic in the GitButler TUI details renderer. Each diff code line (DetailsCodeLine) lazily caches its syntax-highlighted ratatui Line in a RefCell (see crates/but/src/utils/diff_rendering.rs:257); ensure_highlighted() is called immediately before the expect to populate that cache. The panic means the line instance being rendered still has syntax_highlighted_line == None after that call, i.e. the call populated a different instance or was skipped for this line.
Source
Thrown at crates/but/src/command/legacy/status/tui/details.rs:1001
if highlight_lines.is_none() {
let syntax = line.syntax(syntax_set);
*highlight_lines = Some(HighlightLines::new(syntax, syntax_theme));
}
let id = line.id;
let mut strings = self.strings.lock();
line.ensure_highlighted(
syntax_set,
highlight_lines.as_mut().unwrap(),
self.theme,
&mut strings,
);
let syntax_highlighted_line = line.syntax_highlighted_line.borrow();
let syntax_highlighted_line = syntax_highlighted_line
.as_ref()
.expect("line should have been highlighted by now");
if self.section_is_to_be_discarded(id) {
let crossed_out_line = syntax_highlighted_line
.spans
.iter()
.cloned()
.map(|span| span.crossed_out())
.collect::<Line<'_>>()
.style(syntax_highlighted_line.style);
frame.render_widget(crossed_out_line, line_area);
} else {
frame.render_widget(syntax_highlighted_line, line_area);
}
if line
.cli_id
.as_ref()
.is_some_and(|id| marks.contains_cli_id(id))View on GitHub (pinned to 2497b8007a)
Solutions
- Reproduce with RUST_BACKTRACE=1 in a debug build (`cargo run -p but -- status`) and compare the SectionId of the line passed to ensure_highlighted vs the one being borrowed
- Make the invariant local: have ensure_highlighted return the cached Line (or a bool) instead of relying on a separate expect after the call
- Re-run ensure_highlighted for the exact line right before borrowing, guarding against line-list replacement between the two steps
- If an unmodified build panics, report upstream with the backtrace and the displayed section
Example fix
// before (details.rs)
line.ensure_highlighted(syntax_set, highlight_lines.as_mut().unwrap(), self.theme, &mut strings);
let l = line.syntax_highlighted_line.borrow();
let l = l.as_ref().expect("line should have been highlighted by now");
// after — make ensure_highlighted return the populated cache entry
let highlighted = line.ensure_highlighted(syntax_set, hl, self.theme, &mut strings); // returns &Line<'static>
frame.render_widget(highlighted, line_area); Defensive patterns
Strategy: fallback
Validate before calling
// inside a custom render loop, before drawing a code line:
if line.syntax_highlighted_line.borrow().is_none() {
line.ensure_highlighted(syntax_set, highlight_lines, theme, &mut strings);
}
debug_assert!(line.syntax_highlighted_line.borrow().is_some(), "cache still empty for {:?}", line.id); Prevention
- Keep the ensure_highlighted call immediately adjacent to the borrow that reads the cache
- Rebuild cached lines whenever SyntaxSet/theme/highlight state changes instead of reusing stale DetailsCodeLine instances
- Run the details TUI in a subprocess and relaunch on crash — rendering panics should not take down the host process
- Add a render test that expands every section kind so highlight-path regressions fail in CI
When it happens
Trigger: Rendering the expanded details/diff pane (e.g. `but status` TUI with a section expanded) when the DetailsCodeLine being drawn is not the instance ensure_highlighted just filled: diff/line lists rebuilt mid-render (syntax set or theme swap, resize invalidation), or a refactor that drops/reorders the ensure_highlighted call for some line kinds. Note highlight_lines.as_mut().unwrap() just above can panic first if that Option is None.
Common situations: Regression after refactoring Details::render or ensure_highlighted; custom builds that change SyntaxSet/highlighting state while the TUI is running; first render after switching syntax-highlighting themes without rebuilding cached lines.
Related errors
- WithSyntaxHighlighting ensures the line is highlighted
- no searchable columns
- 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
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/0781b5c6fa41bffe.
Report an issue: GitHub.