kovidgoyal/kitty · error · AttributeError

{name} is not a valid color

Error message

{name} is not a valid color

What it means

Raised by __getattr__ in kitty's window title bar color formatter when a color-like attribute name passed to the SGR color formatter cannot be parsed by to_color(). The class synthesizes ANSI escape sequences from attribute names like 'red', '#ff00ff' (via '_ff00ff'), or 'indexed:N', and any name that isn't a recognized color spec raises AttributeError. It is an AttributeError rather than ValueError because it occurs during dynamic attribute access.

Source

Thrown at kitty/window_title_bar.py:67

        elif q == 'window':
            opts = get_options()
            if self.is_active:
                fg_color = _resolve_color(opts.window_title_bar_active_foreground, opts.active_tab_foreground)
                bg_color = _resolve_color(opts.window_title_bar_active_background, opts.active_tab_background)
                col = color_from_int(color_as_int(fg_color if self.which == '3' else bg_color))
            else:
                fg_color = _resolve_color(opts.window_title_bar_inactive_foreground, opts.inactive_tab_foreground)
                bg_color = _resolve_color(opts.window_title_bar_inactive_background, opts.inactive_tab_background)
                col = color_from_int(color_as_int(fg_color if self.which == '3' else bg_color))
            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 WindowTitleFormatter:
    reset = '\x1b[0m'
    fg = WindowTitleColorFormatter('3')
    bg = WindowTitleColorFormatter('4')
    bold = '\x1b[1m'
    nobold = '\x1b[22m'
    italic = '\x1b[3m'
    noitalic = '\x1b[23m'


class WindowTitleData(NamedTuple):
    title: str
    is_active: bool
    window_id: int

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Correct the color name to one kitty's to_color() accepts: standard color names, #RRGGBB (accessed as _RRGGBB), or indexed:N / 8:5:N specs
  2. Validate color strings with kitty.rgb.to_color() before using them as attribute names
  3. If the attribute isn't meant to be a color, rename it so it doesn't collide with __getattr__-based color lookup

Example fix

// before
sgr = formatter.my_colr  # typo -> AttributeError: my_colr is not a valid color

# after
sgr = formatter._ff0000  # explicit hex red, or a name to_color() accepts
Defensive patterns

Strategy: validation

Validate before calling

from kitty.rgb import to_color

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

Type guard

def is_valid_color_name(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:
    sgr = getattr(formatter, name)
except AttributeError as e:
    if 'is not a valid color' in str(e):
        sgr = ''  # skip or use default color
    else:
        raise

Prevention

When it happens

Trigger: Accessing a color attribute on the title-bar formatter object with an invalid name, e.g. formatter.notacolor, formatter._zzzzzz (malformed hex), or an indexed color spec that doesn't parse; any name where to_color(q) returns None.

Common situations: Typos in theme/config color names, using CSS color names kitty doesn't support, malformed hex like '_ff00f' (5 digits), or passing a variable that is None/empty so the attribute name becomes garbage.

Related errors


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