kovidgoyal/kitty · warning
Custom draw tab function failed with error: {e}
Error message
Custom draw tab function failed with error: {e} What it means
A user-supplied draw_tab function (from tab_bar.py) raised at render time; kitty logs the error and falls back to the built-in draw_tab_with_fade so the tab bar still renders.
Source
Thrown at kitty/tab_bar.py:679
log_error(f'Failed to load custom tab_bar.py module with error: {e}')
return {}
@run_once
def load_custom_draw_tab() -> DrawTabFunc:
m = load_custom_draw_tab_module()
func: DrawTabFunc | None = m.get('draw_tab')
if func is None:
return draw_tab_with_fade
@wraps(func)
def draw_tab(
draw_data: DrawData, screen: Screen, tab: TabBarData, before: int, max_tab_length: int, index: int, is_last: bool, extra_data: ExtraData
) -> int:
try:
return func(draw_data, screen, tab, before, max_tab_length, index, is_last, extra_data)
except Exception as e:
log_error(f'Custom draw tab function failed with error: {e}')
return draw_tab_with_fade(draw_data, screen, tab, before, max_tab_length, index, is_last, extra_data)
return draw_tab
def clear_caches() -> None:
load_custom_draw_tab.clear_cached()
load_custom_draw_tab_module.clear_cached()
class CustomDrawTitleFunc:
def __init__(self, data: dict[str, Any], implementation: Callable[[dict[str, Any]], str] | None = None):
self._implementation = implementation
self._data = {} if implementation is None else data.copy()
def __str__(self) -> str:
if self._implementation is None:
return ''View on GitHub (pinned to 6d5d0c4406)
Solutions
- Check kitty's log for the exact exception from your draw_tab
- Guard against edge values: max_tab_length <= 0, missing tab.title, empty extra_data.tabs
- Update tab_bar.py to the current kitty tab bar API and test with 0, 1, and many tabs
Example fix
# before
def draw_tab(dd, screen, tab, before, max_tab_length, index, is_last, extra_data):
return dd.ascent + len(tab.title) // max_tab_length
# after
def draw_tab(dd, screen, tab, before, max_tab_length, index, is_last, extra_data):
if max_tab_length < 1:
return dd.ascent
return dd.ascent + len(tab.title or '') // max_tab_length Defensive patterns
Strategy: try-catch
Try / catch
def draw_tab(dd, screen, tab, before, max_tab_length, index, is_last, extra_data):
try:
return my_draw(dd, screen, tab, before, max_tab_length, index, is_last, extra_data)
except Exception:
return draw_tab_with_fade(dd, screen, tab, before, max_tab_length, index, is_last, extra_data) Prevention
- Guard against max_tab_length <= 0 and empty/None titles
- Test your tab bar with 0, 1, and many tabs before shipping
When it happens
Trigger: The wrapped custom draw_tab in tab_bar.py raises any Exception during tab bar update.
Common situations: Runtime bugs in custom tab bar code (division by zero on max_tab_length, None title, API changes to TabBarData fields) that only manifest with real tabs.
Related errors
- Failed to load custom tab_bar.py module with error: {e}
- The value {val} is not a valid choice for tab_bar_align
- The value {val} is not a valid choice for tab_bar_style
- The value {val} is not a valid choice for tab_powerline_styl
- Invalid tab_bar_margin_height: {x}, ignoring
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/256e16804a6eaa8f.
Report an issue: GitHub.