python/cpython · error · KeySpecError

unrecognised keyname `%s' at char %d of %s

Error message

unrecognised keyname `%s' at char %d of %s

What it means

KeySpecError from _parse_single_key_sequence in Lib/_pyrepl/keymap.py. Inside a \<...> named-key reference, the enclosed name (lowercased by the parser) must exist in the module's _keynames table of recognized key names. An unknown name raises this error with the name and its position in the spec.

Source

Thrown at Lib/_pyrepl/keymap.py:169

                s += 3
            elif c.isdigit():
                n = key[s + 1 : s + 4]
                ret = chr(int(n, 8))
                s += 4
            elif c == "x":
                n = key[s + 2 : s + 4]
                ret = chr(int(n, 16))
                s += 4
            elif c == "<":
                t = key.find(">", s)
                if t == -1:
                    raise KeySpecError(
                        "unterminated \\< starting at char %d of %s"
                        % (s + 1, repr(key))
                    )
                ret = key[s + 2 : t].lower()
                if ret not in _keynames:
                    raise KeySpecError(
                        "unrecognised keyname `%s' at char %d of %s"
                        % (ret, s + 2, repr(key))
                    )
                ret = _keynames[ret]
                s = t + 1
            else:
                raise KeySpecError(
                    "unknown backslash escape %s at char %d of %s"
                    % (repr(c), s + 2, repr(key))
                )
        else:
            ret = key[s]
            s += 1
    if ctrl:
        if len(ret) == 1:
            ret = chr(ord(ret) & 0x1F)  # curses.ascii.ctrl()
        elif ret in {"left", "right"}:
            ret = f"ctrl {ret}"

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Open Lib/_pyrepl/keymap.py and read the _keynames dict; use exactly one of its names inside \<...>.
  2. Common correct names include up, down, left, right, home, end, pgup (not pageup), pgdn, f1..f12, delete, insert, escape, tab.
  3. Validate specs at config load with _parse_single_key_sequence so bad names surface immediately with position info.

Example fix

# before
keymap = {r'\<pageup>': 'scroll-up'}

# after
keymap = {r'\<pgup>': 'scroll-up'}
Defensive patterns

Strategy: validation

Validate before calling

from _pyrepl.keymap import _keynames

def known_keyname(spec):
    import re
    m = re.search(r'\\<([^>]*)>', spec)
    return m is None or m.group(1).lower() in _keynames

Prevention

When it happens

Trigger: Specs like \<pageup> where the table only knows 'pgup', or invented names like \<scroll-up>; the name is lowercased before lookup, so case errors alone do not trigger it, but aliases and abbreviations do.

Common situations: Assuming terminfo/curses key spellings (kf1 vs f1, pgup vs pageup) carry over to pyrepl; version skew where a key name exists in readline/other tools but not in _keynames; typos in config files.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/32c88e2deb2df63c. Report an issue: GitHub.