python/cpython · error · KeySpecError

doubled \M- (char %d of %s)

Error message

doubled \M- (char %d of %s)

What it means

KeySpecError from _parse_single_key_sequence in Lib/_pyrepl/keymap.py. The Meta modifier can appear at most once per key spec; a second \M- while the parser is still looking for the base key raises 'doubled \M-' with the position of the offending token.

Source

Thrown at Lib/_pyrepl/keymap.py:147

                if key[s + 2] != "-":
                    raise KeySpecError(
                        "\\C must be followed by `-' (char %d of %s)"
                        % (s + 2, repr(key))
                    )
                if ctrl:
                    raise KeySpecError(
                        "doubled \\C- (char %d of %s)" % (s + 1, repr(key))
                    )
                ctrl = 1
                s += 3
            elif c == "m":
                if key[s + 2] != "-":
                    raise KeySpecError(
                        "\\M must be followed by `-' (char %d of %s)"
                        % (s + 2, repr(key))
                    )
                if meta:
                    raise KeySpecError(
                        "doubled \\M- (char %d of %s)" % (s + 1, repr(key))
                    )
                meta = 1
                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))

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Drop the duplicate: \M-\M-a -> \M-a.
  2. For a Ctrl+Meta chord use \C-\M-a or \M-\C-a (one of each modifier), never two \M-.
  3. Validate specs at config load with _parse_single_key_sequence.

Example fix

# before
keymap = {r'\M-\M-a': 'accept-line'}

# after
keymap = {r'\M-a': 'accept-line'}
# or a real chord: r'\C-\M-a'
Defensive patterns

Strategy: validation

Validate before calling

import re
def no_doubled_meta(spec):
    return len(re.findall(r'\\[mM]-', spec)) <= 1

Prevention

When it happens

Trigger: Key specs like "\\M-\\M-a" where \M- appears twice before a base character/key is produced. Single legitimate use such as \M-\C-a is fine because each modifier is tracked separately; only duplicate \M- tokens trip this.

Common situations: Double-prefixed Emacs-style bindings copied verbatim; macros or recorded sequences that emit two ESC prefixes; hand-merged keymap entries where a prefix was appended twice.

Related errors


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