kovidgoyal/kitty · error
Failed to open controlling terminal with error: %w
Error message
Failed to open controlling terminal with error: %w
What it means
The SSH kitten opens the controlling terminal (with echo disabled) to run interactively; tty.OpenControllingTerm failed, wrapping the OS error. Usually means stdin/stdout is not attached to a TTY or the terminal device can't be reopened.
Source
Thrown at kittens/ssh/main.go:758
cmcmd = append(cmcmd, "-R", "0:"+listen_on, "-O", "forward")
cmcmd = append(cmcmd, "--", hostname)
c := exec.Command(cmcmd[0], cmcmd[1:]...)
b := bytes.Buffer{}
c.Stdout = &b
c.Stderr = os.Stderr
if err := c.Run(); err != nil {
return 1, fmt.Errorf("%s\nSetup of port forward in SSH ControlMaster failed with error: %w", b.String(), err)
}
port, err := strconv.Atoi(strings.TrimSpace(b.String()))
if err != nil {
os.Stderr.Write(b.Bytes())
return 1, fmt.Errorf("Setup of port forward in SSH ControlMaster failed with error: invalid resolved port returned: %s", b.String())
}
cd.listen_on = "tcp:localhost:" + strconv.Itoa(port)
}
term, err := tty.OpenControllingTerm(tty.SetNoEcho)
if err != nil {
return 1, fmt.Errorf("Failed to open controlling terminal with error: %w", err)
}
cd.echo_on = term.WasEchoOnOriginally()
cd.host_opts, cd.literal_env = host_opts, literal_env
cd.request_data = need_to_request_data
cd.hostname_for_match, cd.username = hostname_for_match, uname
escape_codes_to_set_colors, err := change_colors(cd.host_opts.Color_scheme)
if err == nil {
err = term.WriteAllString(escape_codes_to_set_colors + loop.SAVE_PRIVATE_MODE_VALUES + loop.PUSH_KEY_FLAGS + loop.HANDLE_TERMIOS_SIGNALS.EscapeCodeToSet())
}
if err != nil {
return 1, err
}
restore_escape_codes := loop.RESTORE_PRIVATE_MODE_VALUES + loop.POP_KEY_FLAGS + loop.HANDLE_TERMIOS_SIGNALS.EscapeCodeToReset()
if escape_codes_to_set_colors != "" {
restore_escape_codes += "\x1b[#Q"
}
sigs := make(chan os.Signal, 8)
signal.Notify(sigs, unix.SIGINT, unix.SIGTERM)View on GitHub (pinned to 6d5d0c4406)
Solutions
- Run the ssh kitten inside an interactive kitty window/tab with a real TTY
- If in a container, allocate a TTY (docker run -it / exec -it)
- Avoid piping stdin/stdout into kitty +kitten ssh; use plain ssh for non-interactive use
Example fix
# before (no tty) docker exec mycontainer kitty +kitten ssh host # after docker exec -it mycontainer kitty +kitten ssh host
Defensive patterns
Strategy: validation
Validate before calling
[ -t 0 ] && [ -t 1 ] || { echo 'needs a TTY'; exit 1; } Prevention
- Only run the ssh kitten in an interactive terminal
- Allocate TTYs in containers with -it
When it happens
Trigger: Running the ssh kitten where /dev/tty cannot be opened or set to no-echo — piped stdin/stdout, detached process, container without a TTY, or permissions on the terminal device.
Common situations: Running kitty +kitten ssh from a script, CI, docker exec without -t, or an environment where the process has no controlling terminal.
Related errors
- Could not open controlling terminal with error: %w
- This should be run as kitten ssh
- Incorrect owner on pwfile: uid={shm.stats.st_uid} gid={shm.s
- Incorrect permissions on pwfile: 0o{mode:03o}
- Incorrect password
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/071d8be87d4248cd.
Report an issue: GitHub.