kovidgoyal/kitty · error · Exception
The remote control password was invalid: {data!r}
Error message
The remote control password was invalid: {data!r} What it means
Raised during handler initialization when remote control password negotiation fails: the kitten reads up to 256 bytes from the inherited remote-control socket and expects the response to end with a newline. If the data does not end in b'\n' it means the peer did not send a valid password line (wrong protocol, closed socket, or garbage), so the password cannot be extracted.
Source
Thrown at kittens/tui/handler.py:84
def initialize(self) -> None:
if self.initialized:
return
self.initialized = True
if running_in_kitty():
return
if self.allow_remote_control:
self.to = os.environ.get('KITTY_LISTEN_ON', '')
if not self.to:
raise ValueError('Remote control not enabled, this kitten should be run via a map in kitty.conf, not from the command line')
self.rc_fd = int(self.to.partition(':')[-1])
os.set_inheritable(self.rc_fd, False)
if (self.remote_control_password or self.remote_control_password == '') and not self.password:
import socket
with socket.fromfd(self.rc_fd, socket.AF_UNIX, socket.SOCK_STREAM) as s:
data = s.recv(256)
if not data.endswith(b'\n'):
raise Exception(f'The remote control password was invalid: {data!r}')
self.password = data.strip().decode()
def __call__(self, args: list[str]) -> str:
self.initialize()
return self.func(args)
def allow_indiscriminate_remote_control(self, enable: bool = True) -> None:
if self.rc_fd > -1:
if enable:
os.set_inheritable(self.rc_fd, True)
if self.password:
os.environ['KITTY_RC_PASSWORD'] = self.password
else:
os.set_inheritable(self.rc_fd, False)
if self.password:
os.environ.pop('KITTY_RC_PASSWORD', None)
def remote_control(self, cmd: str | Sequence[str], **kw: Any) -> Any:View on GitHub (pinned to 6d5d0c4406)
Solutions
- Ensure the kitten is launched by the same kitty version that provides the socket (update kitty entirely rather than mixing binaries)
- Launch via a kitty.conf map so FD inheritance is guaranteed
- Pass the password explicitly (set self.password) to skip socket negotiation
Example fix
# before handler = ResultHandler(func, allow_remote_control=True, remote_control_password='') # negotiates over socket # after handler.password = os.environ['KITTY_RC_PASSWORD'] # supply directly, skip negotiation
Defensive patterns
Strategy: try-catch
Try / catch
try:
handler.initialize()
except Exception as e:
if 'remote control password was invalid' in str(e):
handler.password = os.environ.get('KITTY_RC_PASSWORD', '')
else:
raise Prevention
- Pass the password explicitly instead of negotiating over the socket
- Keep kitty and kittens on the same version
- Launch via kitty maps so FD inheritance is intact
When it happens
Trigger: Calling a TUI handler with remote_control_password set (or empty string) and no explicit password, where the socket behind KITTY_LISTEN_ON does not deliver a newline-terminated password line — e.g. the FD points to the wrong socket, an incompatible kitty version, or the socket was already consumed/closed.
Common situations: Mismatched kitty versions between the running terminal and the kitten code; KITTY_LISTEN_ON pointing at another process's socket; the rc_fd inheritance broken by an intermediate wrapper (shell, sandbox, systemd unit) that closed or duplicated FDs.
Related errors
- No password was found
- Password usage requested but KITTY_PUBLIC_KEY environment va
- Failed to parse JSON payload of remote command, ignoring it
- This should be run as kitten icat
- This should be run as `kitten notify ...`
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/185e98f47de7d4a0.
Report an issue: GitHub.