{"record":{"id":"f17b7d1304318c97","repo":"python/cpython","slug":"c-must-be-followed-by-char-d-of-s","errorCode":null,"errorMessage":"\\C must be followed by `-' (char %d of %s)","messagePattern":"\\\\C must be followed by `-' \\(char (.+?) of (.+?)\\)","errorType":"validation","errorClass":"KeySpecError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/keymap.py","lineNumber":130,"sourceCode":"    while s < len(keys):\n        k, s = _parse_single_key_sequence(keys, s)\n        r.extend(k)\n    return r\n\n\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))","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/keymap.py#L112-L148","documentation":"KeySpecError from _parse_single_key_sequence in _pyrepl/keymap.py. When parsing a key specification string, the sequence \\c must be followed by a literal '-' (i.e. \\C-), because the parser only accepts Ctrl modifiers in the canonical \\C-x form. Any other character after \\c triggers this error with the 1-based offset into the spec.","triggerScenarios":"Calling _parse_single_key_sequence (or compiling a keymap whose keys go through it) with a spec containing \\c not followed by '-', e.g. \"\\\\cX\", \"\\\\Cx\", or \"\\\\c[3~\". Case is lowered, so both \\C and \\c are affected.","commonSituations":"Porting readline-style bindings like \\C-x\\C-c into pyrepl config and dropping the dash; copy-pasting key specs from readline docs (which accept ^X notation) into pyrepl keymaps; user keymaps in sitecustomize or REPL plugins.","solutions":["Write the modifier with its dash: \\C-x, not \\cx or \\C-x without the hyphen.","For plain characters use the raw character or a named key like \\<Ctrl-x>-style spelled forms the parser supports; check _keynames for recognized names.","Validate custom key specs at startup by calling _pyrepl.keymap._parse_single_key_sequence on each so config typos fail loudly at load, not at keypress."],"exampleFix":"# before\nkeymap = {r'\\cx': 'cut'}\n\n# after\nkeymap = {r'\\C-x': 'cut'}","handlingStrategy":"validation","validationCode":"from _pyrepl.keymap import _parse_single_key_sequence\n\ndef valid_keyspec(spec):\n    try:\n        _parse_single_key_sequence(spec, 0)\n        return True\n    except Exception:\n        return False\n\nassert valid_keyspec(r'\\C-x'), 'spec must be \\\\C-<key> with dash'","typeGuard":null,"tryCatchPattern":"from _pyrepl.keymap import KeySpecError\ntry:\n    _parse_single_key_sequence(r'\\cx', 0)\nexcept KeySpecError as e:\n    print('bad key spec:', e)","preventionTips":["Always write modifiers as \\C- and \\M- with the hyphen.","Compile/parse custom keymaps once at startup so typos fail fast with positions.","Keep a lint step in tests: parse every key in your keymap dict."],"tags":["python","pyrepl","keymap","parsing","repl"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}