kovidgoyal/kitty · error · ValueError

Could not decode window system key: {q}

Error message

Could not decode window system key: {q}

What it means

send-text with encoding='kitty-key' base64-decodes the payload and tries to interpret it as a window-system key event. If decode_key_event_as_window_system_key returns None the text cannot be mapped to a key and ValueError is raised.

Source

Thrown at kitty/rc/send_text.py:217

                yield from src

        return chain()

    def response_from_kitty(self, boss: Boss, window: Window | None, payload_get: PayloadGetType) -> ResponseType:
        sid = payload_get('session_id', '')
        windows = self.windows_for_payload(boss, window, payload_get, window_match_name='match')
        pdata: str = payload_get('data')
        encoding, _, q = pdata.partition(':')
        session = ''
        if encoding == 'text':
            data: bytes | WindowSystemKeyEvent = q.encode('utf-8')
        elif encoding == 'base64':
            data = base64.standard_b64decode(q)
        elif encoding == 'kitty-key':
            bdata = base64.standard_b64decode(q)
            candidate = decode_key_event_as_window_system_key(bdata.decode('ascii'))
            if candidate is None:
                raise ValueError(f'Could not decode window system key: {q}')
            data = candidate
        elif encoding == 'session':
            session = q
        else:
            raise TypeError(f'Invalid encoding for send-text data: {encoding}')
        exclude_active = payload_get('exclude_active')
        actual_windows = (w for w in windows if w is not None and (not exclude_active or w is not boss.active_window))

        def create_or_update_session() -> Session:
            s = sessions_map.setdefault(sid, Session(sid))
            return s

        if session == 'end':
            s = create_or_update_session()
            for w in actual_windows:
                w.screen.render_unfocused_cursor = False
                s.window_ids.discard(w.id)
            ClearSession(sid)()

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Regenerate the payload using kitty's own key encoding (e.g. kitten @send-text with a recorded key event)
  2. Validate the base64 string decodes to ASCII before sending
  3. Fall back to encoding='text' with base64 for plain text

Example fix

# before
kitten @send-text --encoding kitty-key <bad-b64>
# after
kitten @send-text --encoding base64 "plain text"
Defensive patterns

Strategy: validation

Validate before calling

import base64
from kitty.key_encoding import decode_key_event_as_window_system_key
b = base64.standard_b64decode(payload)
assert decode_key_event_as_window_system_key(b.decode('ascii')) is not None

Try / catch

except ValueError as e: print('bad kitty-key payload', e); fallback to base64 text encoding

Prevention

When it happens

Trigger: Calling kitten @send-text --encoding kitty-key with a base64 string that is not a valid encoded kitty key event (malformed or wrong key name).

Common situations: Hand-crafting kitty-key payloads, or sending key text produced for a different kitty version/key encoding scheme.

Related errors


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