{"record":{"id":"c8e805e19f4b79ba","repo":"python/cpython","slug":"m-must-be-followed-by-char-d-of-s","errorCode":null,"errorMessage":"\\M must be followed by `-' (char %d of %s)","messagePattern":"\\\\M must be followed by `-' \\(char (.+?) of (.+?)\\)","errorType":"validation","errorClass":"KeySpecError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/keymap.py","lineNumber":142,"sourceCode":"            c = key[s + 1].lower()\n            if c in _escapes:\n                ret = _escapes[c]\n                s += 2\n            elif c == \"c\":\n                if key[s + 2] != \"-\":\n                    raise KeySpecError(\n                        \"\\\\C must be followed by `-' (char %d of %s)\"\n                        % (s + 2, repr(key))\n                    )\n                if ctrl:\n                    raise KeySpecError(\n                        \"doubled \\\\C- (char %d of %s)\" % (s + 1, repr(key))\n                    )\n                ctrl = 1\n                s += 3\n            elif c == \"m\":\n                if key[s + 2] != \"-\":\n                    raise KeySpecError(\n                        \"\\\\M must be followed by `-' (char %d of %s)\"\n                        % (s + 2, repr(key))\n                    )\n                if meta:\n                    raise KeySpecError(\n                        \"doubled \\\\M- (char %d of %s)\" % (s + 1, repr(key))\n                    )\n                meta = 1\n                s += 3\n            elif c.isdigit():\n                n = key[s + 1 : s + 4]\n                ret = chr(int(n, 8))\n                s += 4\n            elif c == \"x\":\n                n = key[s + 2 : s + 4]\n                ret = chr(int(n, 16))\n                s += 4\n            elif c == \"<\":","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/keymap.py#L124-L160","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the canonical form \\M-x with the dash.","Prefer composing Meta as an actual ESC prefix only if the parser supports it in your version; otherwise stick to \\M-.","Run custom specs through _parse_single_key_sequence during config load to fail fast."],"exampleFix":"# before\nkeymap = {r'\\mx': 'next-history'}\n\n# after\nkeymap = {r'\\M-x': 'next-history'}","handlingStrategy":"validation","validationCode":"import re\ndef valid_meta(spec):\n    # every \\m / \\M must be followed by '-'\n    return not re.search(r'\\\\[mM](?!-)', spec)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Write \\M-x with the dash, never \\mx.","Do not transliterate Emacs 'M-x' notation literally.","Test-parse custom keymaps at startup."],"tags":["python","pyrepl","keymap","parsing","repl"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}