kovidgoyal/kitty · error · ValueError

Remote control is not enabled, remember to use allow_remote_

Error message

Remote control is not enabled, remember to use allow_remote_control=True

What it means

Raised by remote_control() when the handler was created without allow_remote_control=True. The method builds a 'kitten @' command line to talk to kitty's remote control socket; if the flag was not set at construction, no socket/password setup happened, so the call is refused with a corrective hint.

Source

Thrown at kittens/tui/handler.py:104

    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:
        if not self.allow_remote_control:
            raise ValueError('Remote control is not enabled, remember to use allow_remote_control=True')
        prefix = [kitten_exe(), '@']
        r = -1
        pass_fds = list(kw.get('pass_fds') or [])
        try:
            if self.rc_fd > -1:
                pass_fds.append(self.rc_fd)
            if self.password and self.rc_fd > -1:
                r, w = safe_pipe(False)
                os.write(w, self.password.encode())
                os.close(w)
                prefix += ['--password-file', f'fd:{r}', '--use-password', 'always']
                pass_fds.append(r)
            if pass_fds:
                kw['pass_fds'] = tuple(pass_fds)
            if isinstance(cmd, str):
                cmd = ' '.join(prefix)
            else:
                cmd = prefix + list(cmd)

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Pass allow_remote_control=True when constructing the handler
  2. Ensure the kitten runs via a kitty.conf map so KITTY_LISTEN_ON exists (required once the flag is on)
  3. Restructure so remote_control is only called on handlers known to have the flag set

Example fix

# before
handler = ResultHandler(func)  # allow_remote_control defaults to False
handler.remote_control('send-text', text='hi')
# after
handler = ResultHandler(func, allow_remote_control=True)
handler.remote_control('send-text', text='hi')
Defensive patterns

Strategy: type-guard

Validate before calling

if not handler.allow_remote_control:
    raise SystemExit('re-create handler with allow_remote_control=True')

Type guard

from kittens.tui.handler import ResultHandler
def supports_remote_control(h: ResultHandler) -> bool:
    return bool(getattr(h, 'allow_remote_control', False))

Try / catch

try:
    handler.remote_control(cmd)
except ValueError as e:
    if 'allow_remote_control=True' in str(e):
        # recreate handler with the flag and retry
        raise
    raise

Prevention

When it happens

Trigger: Calling handler.remote_control('set-color', ...) on a handler instantiated with allow_remote_control=False (the default), e.g. when a generic TUI handler is reused and later decides it needs remote control.

Common situations: Copy-pasting a kitten that uses remote_control into a handler created by a base class or template that passes allow_remote_control=False; refactoring where the flag gets lost; conditional code paths that only sometimes need remote control.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/933a5d5c3c727b5c. Report an issue: GitHub.