kovidgoyal/kitty · error · AttributeError

{name} is not a valid color

Error message

{name} is not a valid color

What it means

Raised by the tab-bar Formatter's __getattr__ when an attribute name is neither a known style key nor parseable as a color. Attribute access like formatter.red or formatter._ff0000 is dynamically converted to SGR escape codes; anything to_color() cannot parse raises AttributeError with this message. Because it's an AttributeError, hasattr() and getattr(default) interact with it normally.

Source

Thrown at kitty/tab_bar.py:170

    def __init__(self, which: str):
        self.which = which

    def __getattr__(self, name: str) -> str:
        q = name
        if q == 'default':
            ans = '9'
        elif q == 'tab':
            col = color_from_int((self.draw_data.tab_bg if self.which == '4' else self.draw_data.tab_fg)(self.tab_data))
            ans = f'8{color_as_sgr(col)}'
        elif q.startswith('color'):
            ans = f'8:5:{int(q[5:])}'
        else:
            if name.startswith('_'):
                q = f'#{name[1:]}'
            c = to_color(q)
            if c is None:
                raise AttributeError(f'{name} is not a valid color')
            ans = f'8{color_as_sgr(c)}'
        return f'\x1b[{self.which}{ans}m'


class Formatter:
    reset = '\x1b[0m'
    fg = ColorFormatter('3')
    bg = ColorFormatter('4')
    bold = '\x1b[1m'
    nobold = '\x1b[22m'
    italic = '\x1b[3m'
    noitalic = '\x1b[23m'


@run_once
def super_sub_maps() -> tuple[dict[int, int], dict[int, int]]:
    import string

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Use a valid color name ('red'), 256-color index ('color123'), or _RRGGBB hex form
  2. Use getattr(formatter, 'attr', None) or hasattr to probe optional styles
  3. Check kitty's tab_bar.py for the supported attribute vocabulary

Example fix

# before
fg = formatter._zzzzzz
# after
fg = formatter._ff0000  # or formatter.red
Defensive patterns

Strategy: fallback

Validate before calling

from kitty.rgb import to_color
if to_color(name.lstrip('_').prepend('#') if name.startswith('_') else name) is None:
    style = formatter.reset

Type guard

def is_valid_formatter_color(name: str) -> bool:
    from kitty.rgb import to_color
    q = f'#{name[1:]}' if name.startswith('_') else name
    return to_color(q) is not None

Try / catch

try:
    seq = getattr(formatter, token)
except AttributeError:
    seq = formatter.reset

Prevention

When it happens

Trigger: Accessing a Formatter attribute that isn't a color, e.g. formatter.not_a_color, or a malformed hex like formatter._gggggg (after '#' substitution to_color fails).

Common situations: Typos in tab-bar.py color names; using an unsupported color syntax in a custom tab bar style function; checking hasattr(formatter, 'bold') style keys that don't exist.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/8f35db3ca1e480f2. Report an issue: GitHub.