kovidgoyal/kitty · error

Failed to start SSH ControlMaster with cmdline: %s and error

Error message

Failed to start SSH ControlMaster with cmdline: %s and error: %w

What it means

When a shared connection is requested but no live ControlMaster exists, the kitten execs 'ssh -N -f ...' to start one; c.Run() failed (non-zero exit or spawn failure). The full command line and the underlying error are wrapped in this message.

Source

Thrown at kittens/ssh/main.go:713

		// slices.Insert can mutate cmd's backing array in place; clone so cmd stays intact
		check_cmd := slices.Insert(slices.Clone(cmd), 1, "-O", "check")
		master_is_alive = exec.Command(check_cmd[0], check_cmd[1:]...).Run() == nil
		return master_is_alive
	}

	if need_to_request_data && host_opts.Share_connections && master_is_functional() {
		need_to_request_data = false
	}
	run_control_master := func() error {
		cmcmd := slices.Clone(cmd[:insertion_point])
		cmcmd = append(cmcmd, control_master_args...)
		cmcmd = append(cmcmd, "-N", "-f")
		cmcmd = append(cmcmd, "--", hostname)
		c := exec.Command(cmcmd[0], cmcmd[1:]...)
		c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr
		err := c.Run()
		if err != nil {
			err = fmt.Errorf("Failed to start SSH ControlMaster with cmdline: %s and error: %w", strings.Join(cmcmd, " "), err)
		}
		master_checked = false
		master_is_alive = false
		return err
	}
	if host_opts.Forward_remote_control && os.Getenv("KITTY_LISTEN_ON") != "" {
		if !host_opts.Share_connections {
			return 1, fmt.Errorf("Cannot use forward_remote_control=yes without share_connections=yes as it relies on SSH Controlmasters")
		}
		if !master_is_functional() {
			if err = run_control_master(); err != nil {
				return 1, err
			}
			if !master_is_functional() {
				return 1, fmt.Errorf("SSH ControlMaster not functional after being started explicitly")
			}
		}
		protocol, listen_on, found := strings.Cut(os.Getenv("KITTY_LISTEN_ON"), ":")

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Reproduce manually with the cmdline from the error message (without -f) to see ssh's real error
  2. Verify auth works: ssh -o ControlPath=none user@host true
  3. Check ControlPath in ssh_config — use a directory that exists (%C-style paths auto-create in newer OpenSSH)
  4. Clear stale sockets: rm -rf ~/.local/share/kitty/ssh-control-master/* or your ControlPath dir
  5. Disable share_connections for the problematic host as a workaround

Example fix

# before: kitty.conf has share_connections yes, master fails
# debug manually:
ssh -vvv -o ControlPath='/tmp/%r@%h:%p' -N user@host
# after: fix ControlPath to an existing dir
Host *
  ControlPath ~/.local/share/kitty/cm-%C
mkdir -p ~/.local/share/kitty
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight the master manually:
// ssh -o ControlPath=<path> -N -f user@host || handle auth/config issue first

Try / catch

if err := startControlMaster(cmcmd); err != nil {
    if strings.Contains(err.Error(), "Failed to start SSH ControlMaster") {
        // retry once without -f to capture the real ssh error, then surface it
    }
}

Prevention

When it happens

Trigger: The master bootstrap ssh process failing: authentication failure (no keys/agent), unknown hostname, ssh config errors, ControlPath directory uncreatable, or the ssh binary itself erroring under -N -f.

Common situations: First connection to a host without valid credentials; ControlPath pointing to a non-existent directory with no auto-create; sshd refusing ControlMaster; ProxyCommand failing; ssh versions disallowing -f combos; too many stale master sockets exhausting the multiplex dir.

Related errors


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