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
- Remove or rename one of the conflicting bindings — a key can be either an action or a prefix for further keys, not both.
- If you need a chord, do not bind the bare prefix key to an action; leave it unbound so the trie can descend.
- 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
- Never bind both a key and a longer chord sharing that key as prefix.
- Compile keymaps in unit tests to catch clashes before shipping.
- When merging keymaps, run a prefix-overlap check first.
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
- \C must be followed by `-' (char %d of %s)
- doubled \C- (char %d of %s)
- \M must be followed by `-' (char %d of %s)
- doubled \M- (char %d of %s)
- unterminated \< starting at char %d of %s
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/9d620495306b1653.
Report an issue: GitHub.