{"record":{"id":"6c6e5ab8e4da15fe","repo":"python/cpython","slug":"unknown-backslash-escape-s-at-char-d-of-s","errorCode":null,"errorMessage":"unknown backslash escape %s at char %d of %s","messagePattern":"unknown backslash escape (.+?) at char (.+?) of (.+?)","errorType":"validation","errorClass":"KeySpecError","httpStatus":null,"severity":"error","filePath":"Lib/_pyrepl/keymap.py","lineNumber":176,"sourceCode":"                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))\n                    )\n                ret = key[s + 2 : t].lower()\n                if ret not in _keynames:\n                    raise KeySpecError(\n                        \"unrecognised keyname `%s' at char %d of %s\"\n                        % (ret, s + 2, repr(key))\n                    )\n                ret = _keynames[ret]\n                s = t + 1\n            else:\n                raise KeySpecError(\n                    \"unknown backslash escape %s at char %d of %s\"\n                    % (repr(c), s + 2, repr(key))\n                )\n        else:\n            ret = key[s]\n            s += 1\n    if ctrl:\n        if len(ret) == 1:\n            ret = chr(ord(ret) & 0x1F)  # curses.ascii.ctrl()\n        elif ret in {\"left\", \"right\"}:\n            ret = f\"ctrl {ret}\"\n        else:\n            raise KeySpecError(\"\\\\C- followed by invalid key\")\n\n    result = [ret], s\n    if meta:\n        result[0].insert(0, \"\\033\")\n    return result","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyrepl/keymap.py#L158-L194","documentation":"KeySpecError from _parse_single_key_sequence in Lib/_pyrepl/keymap.py. After a backslash, the next character must be one of the recognized escapes: _escapes entries, 'c' (\\C-), 'm' (\\M-), octal digits, 'x' (hex), or '<' (named key). Anything else is an unknown backslash escape and raises this error showing the offending character.","triggerScenarios":"Specs containing an escape the parser does not know, e.g. \"\\\\e\" is fine (in _escapes) but \"\\\\z\", \"\\\\t\" only if 't' is in _escapes, or Windows-style \"\\\\\\\\\" handling mistakes; also single trailing backslash where key[s+1] indexing grabs a wrong char.","commonSituations":"Porting readline init syntax (which supports more escapes) into pyrepl keymaps; platform path-separator backslashes leaking into key specs; assuming \\n/\\r/\\t spellings without checking _escapes in the module.","solutions":["Check the _escapes dict at the top of Lib/_pyrepl/keymap.py and use only its escape letters.","For control/meta use \\C- and \\M-; for named keys use \\<name>; for arbitrary chars use octal (\\NNN) or hex (\\xNN) forms.","Strip/escape stray backslashes from dynamically built spec strings before parsing."],"exampleFix":"# before\nkeymap = {r'\\z': 'foo'}\n\n# after\n# use hex escape for the literal char, e.g. Ctrl-Z is \\C-z or \\x1a\nkeymap = {r'\\C-z': 'foo'}","handlingStrategy":"validation","validationCode":"from _pyrepl.keymap import _escapes, _keynames\n\ndef only_known_escapes(spec):\n    import re\n    for m in re.finditer(r'\\\\(.)', spec):\n        c = m.group(1).lower()\n        if c not in _escapes and c not in 'cmx<' and not c.isdigit():\n            return False\n    return True","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict escapes to the module's _escapes table plus \\C-, \\M-, octal \\NNN, hex \\xNN, \\<name>.","Sanitize path-like strings before they reach key-spec code.","Parse specs in tests to surface unknown escapes."],"tags":["python","pyrepl","keymap","parsing","escapes"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}