{"record":{"id":"ce18a16d47ad0e5f","repo":"python/cpython","slug":"doubled-c-char-d-of-s","errorCode":null,"errorMessage":"doubled \\C- (char %d of %s)","messagePattern":"doubled \\\\C- \\(char (.+?) of (.+?)\\)","errorType":"validation","errorClass":"KeySpecError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/keymap.py","lineNumber":135,"sourceCode":"\ndef _parse_single_key_sequence(key: str, s: int) -> tuple[list[str], int]:\n    ctrl = 0\n    meta = 0\n    ret = \"\"\n    while not ret and s < len(key):\n        if key[s] == \"\\\\\":\n            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]","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/keymap.py#L117-L153","documentation":"KeySpecError from _parse_single_key_sequence in Lib/_pyrepl/keymap.py. The Ctrl modifier may only be applied once per key spec; a second \\C- occurrence in the same spec (while the parser is still accumulating the key) raises this 'doubled \\C-' error with the position of the duplicate.","triggerScenarios":"A key spec containing two \\C- tokens before a base key is produced, e.g. \"\\\\C-\\\\C-a\" or \"\\\\C-x\\\\C-c\" is fine only because parsing restarts per sequence — the error fires when the second \\C- appears while ret is still empty, e.g. \"\\\\C-\\\\C-a\".","commonSituations":"Mistakenly doubling modifiers when translating readline bindings (readline tolerates ^ prefix stacking in some macros); hand-edited keymap tables; macros recorded with doubled control prefixes.","solutions":["Remove the duplicate modifier: \\C-\\C-a should be just \\C-a.","If you intended a two-key chord, keep them as two separate specs/events — the parser returns one key per call, chords are built at the keymap level.","Lint custom keymaps through _parse_single_key_sequence at startup to catch doubled modifiers early."],"exampleFix":"# before\nkeymap = {r'\\C-\\C-a': 'beginning-of-line'}\n\n# after\nkeymap = {r'\\C-a': 'beginning-of-line'}","handlingStrategy":"validation","validationCode":"import re\n\ndef no_doubled_ctrl(spec):\n    return len(re.findall(r'\\\\[cC]-', spec)) <= 1","typeGuard":null,"tryCatchPattern":null,"preventionTips":["One \\C- per key spec; chords are separate specs.","Parse specs with _parse_single_key_sequence at config load.","When merging keymaps, check for duplicated modifier tokens."],"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"}