kovidgoyal/kitty · error · KeyError

No option named: {k}

Error message

No option named: {k}

What it means

Generated options classes (__getitem__) raise KeyError('No option named: {k}') when looking up an option name that the parsed configuration does not define. This code lives in the generated conf class emitted by generate_class.

Source

Thrown at kitty/conf/generate.py:270

    a('        return {k: self._copy_of_val(k) for k in self}')

    a('')
    a('    def _replace(self, **kw: typing.Any) -> "Options":')
    a('        ans = Options()')
    a('        for name in self:')
    a('            setattr(ans, name, self._copy_of_val(name))')
    a('        for name, val in kw.items():')
    a('            setattr(ans, name, val)')
    a('        return ans')

    a('')
    a('    def __getitem__(self, key: int | str) -> typing.Any:')
    a('        k = option_names[key] if isinstance(key, int) else key')
    a('        try:')
    a('            return getattr(self, k)')
    a('        except AttributeError:')
    a('            pass')
    a('        raise KeyError(f"No option named: {k}")')

    if defn.has_color_table:
        a('')
        a('    def __getattr__(self, key: str) -> typing.Any:')
        a('        if key.startswith("color"):')
        a('            q = key[5:]')
        a('            if q.isdigit():')
        a('                k = int(q)')
        a('                if 0 <= k <= 255:')
        a('                    x = self.color_table[k]')
        a(f'                    if x == 0x{NULL_COLOR_VALUE:x}:')
        a('                        return None')
        a('                    return Color((x >> 16) & 255, (x >> 8) & 255, x & 255)')
        a('        raise AttributeError(key)')
        a('')
        a('    def __setattr__(self, key: str, val: typing.Any) -> typing.Any:')
        a('        if key.startswith("color"):')
        a('            q = key[5:]')

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Check the exact option name in kitty's options docs
  2. Use option_names / as_dict() to list valid keys
  3. Pin or upgrade versions consistently between generating and consuming code

Example fix

# before
val = opts['font_sz']
# after
val = opts['font_size']
Defensive patterns

Strategy: validation

Validate before calling

from kitty.conf.utils import *  # generated class dependent
valid = set(opts.option_names) if hasattr(opts, 'option_names') else set(opts.as_dict())
if key not in valid:
    raise KeyError(f'{key} not valid; valid: {sorted(valid)[:10]}...')

Type guard

def has_option(opts, name: str) -> bool:
    try:
        opts[name]
        return True
    except KeyError:
        return False

Try / catch

try:
    val = opts[key]
except KeyError as e:
    if 'No option named' in str(e):
        val = default_for(key)
    else:
        raise

Prevention

When it happens

Trigger: options['nonexistent_option'] or options[bad_index] on a parsed Options object where getattr raises AttributeError and the name is not in option_names.

Common situations: Typos in option names in scripts using the options mapping API, or accessing options that were removed/renamed between kitty versions.

Related errors


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