python/cpython · error · KeySpecError

key definitions for %s clash

Error message

key definitions for %s clash

What it means

KeySpecError from compile_keymap in Lib/_pyrepl/keymap.py. Keymaps are compiled into a trie keyed by first character with the remainder as a sub-key; the empty remainder marks a complete binding. If one key is a strict prefix of another in the same map (e.g. \C-x and \C-x\C-c), the empty-remainder entry collides with real sub-keys and the definitions are said to clash.

Source

Thrown at Lib/_pyrepl/keymap.py:208

    result = [ret], s
    if meta:
        result[0].insert(0, "\033")
    return result


def compile_keymap(keymap, empty=b""):
    r = {}
    for key, value in keymap.items():
        if isinstance(key, bytes):
            first = key[:1]
        else:
            first = key[0]
        r.setdefault(first, {})[key[1:]] = value
    for key, value in r.items():
        if empty in value:
            if len(value) != 1:
                raise KeySpecError("key definitions for %s clash" % (value.values(),))
            else:
                r[key] = value[empty]
        else:
            r[key] = compile_keymap(value, empty)
    return r

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Remove or rename one of the conflicting bindings — a key can be either an action or a prefix for further keys, not both.
  2. If you need a chord, do not bind the bare prefix key to an action; leave it unbound so the trie can descend.
  3. Pre-compile keymaps in tests via _pyrepl.keymap.compile_keymap so clashes fail in CI rather than at REPL startup.

Example fix

# before
keymap = {
    r'\C-x': 'exit',
    r'\C-x\C-c': 'exit',
}

# after
keymap = {r'\C-x\C-c': 'exit'}
Defensive patterns

Strategy: validation

Validate before calling

def no_prefix_clash(keymap):
    keys = [k for k in keymap if isinstance(k, str)]
    for a in keys:
        for b in keys:
            if a != b and b.startswith(a):
                return False
    return True

Try / catch

from _pyrepl.keymap import KeySpecError, compile_keymap
try:
    compile_keymap(my_keymap)
except KeySpecError as e:
    print('clash:', e)

Prevention

When it happens

Trigger: compile_keymap on a dict where both a shorter sequence and longer sequences sharing it as a prefix are bound, e.g. {'x': f1, 'xy': f2} or {'\\C-x': 'cmd1', '\\C-x\\C-c': 'cmd2'}; the check 'empty in value and len(value) != 1' is exactly this conflict.

Common situations: Merging keymaps from multiple plugins that bind a prefix and an extension of it; defining both a single-key command and a chord starting with the same key; refactoring keymaps and leaving stale shorter bindings in place.

Related errors


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