{"record":{"id":"19f85e4d6d1bdde5","repo":"python/cpython","slug":"doubled-m-char-d-of-s","errorCode":null,"errorMessage":"doubled \\M- (char %d of %s)","messagePattern":"doubled \\\\M- \\(char (.+?) of (.+?)\\)","errorType":"validation","errorClass":"KeySpecError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/keymap.py","lineNumber":147,"sourceCode":"                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 == \"<\":\n                t = key.find(\">\", s)\n                if t == -1:\n                    raise KeySpecError(\n                        \"unterminated \\\\< starting at char %d of %s\"\n                        % (s + 1, repr(key))","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/keymap.py#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Drop the duplicate: \\M-\\M-a -> \\M-a.","For a Ctrl+Meta chord use \\C-\\M-a or \\M-\\C-a (one of each modifier), never two \\M-.","Validate specs at config load with _parse_single_key_sequence."],"exampleFix":"# before\nkeymap = {r'\\M-\\M-a': 'accept-line'}\n\n# after\nkeymap = {r'\\M-a': 'accept-line'}\n# or a real chord: r'\\C-\\M-a'","handlingStrategy":"validation","validationCode":"import re\ndef no_doubled_meta(spec):\n    return len(re.findall(r'\\\\[mM]-', spec)) <= 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["At most one \\M- per spec; combine modifiers as \\C-\\M-x instead.","Lint merged keymap entries for repeated modifier tokens.","Parse each spec via _parse_single_key_sequence in CI."],"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"}