{"record":{"id":"5c918f1857c6da2b","repo":"kovidgoyal/kitty","slug":"incorrect-request-id-rq-id-r-expecting-the-kitt","errorCode":null,"errorMessage":"Incorrect request id: {rq_id!r} expecting the KITTY_PID-KITTY_WINDOW_ID for the current kitty window","messagePattern":"Incorrect request id: (.+?) expecting the KITTY_PID-KITTY_WINDOW_ID for the current kitty window","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"kittens/ssh/utils.py","lineNumber":197,"sourceCode":"    from base64 import standard_b64decode\n\n    yield b'\\nKITTY_DATA_START\\n'  # to discard leading data\n    try:\n        msg = standard_b64decode(msgb).decode('utf-8')\n        md = dict(x.split('=', 1) for x in msg.split(':'))\n        pw = md['pw']\n        pwfilename = md['pwfile']\n        rq_id = md['id']\n    except Exception:\n        traceback.print_exc()\n        yield b'invalid ssh data request message\\n'\n    else:\n        try:\n            env_data = read_data_from_shared_memory(pwfilename)\n            if pw != env_data['pw']:\n                raise ValueError('Incorrect password')\n            if rq_id != request_id:\n                raise ValueError(f'Incorrect request id: {rq_id!r} expecting the KITTY_PID-KITTY_WINDOW_ID for the current kitty window')\n        except Exception as e:\n            traceback.print_exc()\n            import re\n\n            msg = re.sub(r'[^a-zA-Z0-9 ]+', '_', str(e))\n            yield f'{msg}\\n'.encode()\n        else:\n            yield b'OK\\n'\n            encoded_data = memoryview(env_data['tarfile'].encode('ascii'))\n            # macOS has a 255 byte limit on its input queue as per man stty.\n            # Not clear if that applies to canonical mode input as well, but\n            # better to be safe.\n            line_sz = 254\n            while encoded_data:\n                yield encoded_data[:line_sz]\n                yield b'\\n'\n                encoded_data = encoded_data[line_sz:]\n            yield b'KITTY_DATA_END\\n'","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/ssh/utils.py#L179-L215","documentation":"get_ssh_data() validates that the request id (rq_id) parsed from the incoming request equals the request_id it computed for the current connection, which is derived from KITTY_PID-KITTY_WINDOW_ID of the current kitty window. A mismatch raises ValueError('Incorrect request id: ...'); the handler catches it, prints the traceback, and yields a regex-sanitized error message back to the requester.","triggerScenarios":"handle_remote_ssh() or a hand-rolled client sends a request whose rq_id isn't the KITTY_PID-KITTY_WINDOW_ID of the window that owns the pwfile — e.g. after kitty restarted (new PID) while a remote ssh wrapper still had the old id, multiple windows sharing shm state, or a manually crafted request message.","commonSituations":"kitty was restarted or the window closed/reopened during a remote ssh kitten session; KITTY_PID/KITTY_WINDOW_ID env vars exported into a different shell/session and reused; scripts shelling the ssh kitten protocol from outside kitty; tmux/screen inside kitty propagating stale kitty env vars to a later session.","solutions":["Re-run the ssh command from the current kitty window so KITTY_PID-KITTY_WINDOW_ID match the live window.","unset/sanitize exported KITTY_PID and KITTY_WINDOW_ID in shells that outlive their kitty window (add to shell rc hygiene).","Restart the remote ssh kitten wrapper if kitty restarted mid-session; the old ids are permanently invalid.","If scripting the protocol, derive request_id from the current window's env, never hardcode it."],"exampleFix":"# before (stale env in a long-lived shell)\nexport KITTY_PID=1234 KITTY_WINDOW_ID=2  # kitty restarted, PID is gone\nkitten ssh host  # -> Incorrect request id\n\n# after\nunset KITTY_PID KITTY_WINDOW_ID\n# open a fresh kitty window and run kitten ssh host there","handlingStrategy":"validation","validationCode":"import os\n\ndef current_request_id() -> str | None:\n    pid, wid = os.environ.get('KITTY_PID'), os.environ.get('KITTY_WINDOW_ID')\n    if not pid or not wid:\n        return None  # not inside a live kitty window; don't attempt the handshake\n    return f'{pid}-{wid}'\n\n# only proceed when this matches the id the pwfile was created with","typeGuard":null,"tryCatchPattern":"try:\n    ...  # perform ssh data request\nexcept Exception as e:\n    if 'Incorrect request id' in str(e):\n        refresh_kitty_env_or_restart_session()  # stale KITTY_PID/KITTY_WINDOW_ID\n    else:\n        raise","preventionTips":["Scrub KITTY_PID/KITTY_WINDOW_ID from shells/tmux panes that outlive their kitty window (e.g. in shell rc: [ -n \"$TMUX\" ] && unset KITTY_PID KITTY_WINDOW_ID when the window is gone).","Re-init remote ssh sessions after restarting kitty.","Never hardcode request ids when scripting the ssh kitten protocol; read them from the live environment."],"tags":["kitty","ssh","request-id","stale-environment","ipc"],"backgroundTag":"stale-session-id-handshake","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}