python/cpython · error · KeySpecError

\M must be followed by `-' (char %d of %s)

Error message

\M must be followed by `-' (char %d of %s)

What it means

KeySpecError from _parse_single_key_sequence in Lib/_pyrepl/keymap.py. The Meta/Alt modifier escape \m must be written \M- with a literal dash; any other character after \m raises this error, mirroring the \C- rule for Ctrl. The message includes the 1-based character position in the spec.

Source

Thrown at Lib/_pyrepl/keymap.py:142

            c = key[s + 1].lower()
            if c in _escapes:
                ret = _escapes[c]
                s += 2
            elif c == "c":
                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 == "<":

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Use the canonical form \M-x with the dash.
  2. Prefer composing Meta as an actual ESC prefix only if the parser supports it in your version; otherwise stick to \M-.
  3. Run custom specs through _parse_single_key_sequence during config load to fail fast.

Example fix

# before
keymap = {r'\mx': 'next-history'}

# after
keymap = {r'\M-x': 'next-history'}
Defensive patterns

Strategy: validation

Validate before calling

import re
def valid_meta(spec):
    # every \m / \M must be followed by '-'
    return not re.search(r'\\[mM](?!-)', spec)

Prevention

When it happens

Trigger: Key specs where \m is not followed by '-', such as "\\Ma" or "\\meta-x"; the escape letter is lowercased so both \M and \m are checked.

Common situations: Users accustomed to Emacs 'M-x' or readline '\M-x' shorthand writing \mx; converting terminal escape tables where ESC-prefixed keys are described as \M<key> without the dash; typos in custom pyrepl keymaps.

Related errors


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