jesseduffield/lazydocker · error

ssh tunneled socket never became available: %w

Error message

ssh tunneled socket never became available: %w

What it means

After starting `ssh -L`, createDockerHostTunnel waits up to 8 seconds (retrySocketDial ticks every second) for the local unix socket to accept a connection. This error means the tunnel process started but the socket never became dialable before the context deadline — the %w chain ends in context.DeadlineExceeded. It distinguishes 'ssh could not even start' from 'ssh started but the forward never worked'.

Source

Thrown at pkg/commands/ssh/ssh.go:108

	if err != nil {
		return nil, fmt.Errorf("create ssh tunnel tmp file: %w", err)
	}
	localSocket := path.Join(socketDir, "dockerhost.sock")

	cmd, err := self.tunnelSSH(ctx, remoteHost, localSocket)
	if err != nil {
		return nil, fmt.Errorf("tunnel docker host over ssh: %w", err)
	}

	// set a reasonable timeout, then wait for the socket to dial successfully
	// before attempting to create a new docker client
	const socketTunnelTimeout = 8 * time.Second
	ctx, cancel := context.WithTimeout(ctx, socketTunnelTimeout)
	defer cancel()

	err = self.retrySocketDial(ctx, localSocket)
	if err != nil {
		return nil, fmt.Errorf("ssh tunneled socket never became available: %w", err)
	}

	// construct the new DOCKER_HOST url with the proper scheme
	newDockerHostURL := url.URL{Scheme: "unix", Path: localSocket}
	return &tunneledDockerHost{
		socketPath: newDockerHostURL.String(),
		cmd:        cmd,
		oSCommand:  self.oSCommand,
	}, nil
}

// Attempt to dial the socket until it becomes available.
// The retry loop will continue until the parent context is canceled.
func (self *SSHHandler) retrySocketDial(ctx context.Context, socketPath string) error {
	t := time.NewTicker(1 * time.Second)
	defer t.Stop()

	for {

View on GitHub (pinned to 7e7aadc207)

Solutions

  1. Connect once manually to accept the host key: `ssh user@host echo ok` (fixes 'host key verification failed' stalls).
  2. Ensure non-interactive auth works: load keys with ssh-agent, or use a passphrase-less dedicated key via ~/.ssh/config.
  3. Confirm the remote socket path exists at /var/run/docker.sock (`ssh host ls /var/run/docker.sock`); for rootless docker, forward manually (`ssh -L /tmp/d.sock:/run/user/1000/docker.sock host -N &`) and set DOCKER_HOST=unix:///tmp/d.sock.
  4. On slow links, retry lazydocker — the 8s budget is fixed in code, so pre-warming the connection (manual ssh first) helps.

Example fix

# before
DOCKER_HOST=ssh://user@newhost lazydocker  # first connect: host-key prompt stalls -> timeout

# after
ssh user@newhost echo ok   # accept host key once
eval $(ssh-agent) && ssh-add
DOCKER_HOST=ssh://user@newhost lazydocker
Defensive patterns

Strategy: retry

Validate before calling

// preflight the exact tunnel lazydocker will build
probe := exec.Command("ssh", "-o", "BatchMode=yes", "-L", "/tmp/probe.sock:/var/run/docker.sock", host, "-N")
if err := probe.Start(); err == nil {
    defer probe.Process.Kill()
} else {
    return fmt.Errorf("ssh tunnel preflight failed: %w", err)
}

Try / catch

closer, err := sshHandler.LearnDockerHostShim()
if err != nil && strings.Contains(err.Error(), "never became available") {
    time.Sleep(2 * time.Second)
    closer, err = sshHandler.LearnDockerHostShim() // one retry: slow first-connect
}

Prevention

When it happens

Trigger: ssh is running but the forward is broken or too slow to establish: authentication stalls (passphrase prompt, disabled host-key acceptance in non-interactive mode), the remote /var/run/docker.sock does not exist, sshd on the remote refuses the forward (AllowTcpForwarding no / disabled unix forwarding), or the host is unreachable so ssh retries until the 8s budget runs out.

Common situations: First connection to a new host (host-key verification fails because lazydocker's ssh is non-interactive); key with passphrase and no agent; rootless docker on the remote (socket at /run/user/$UID/docker.sock, not /var/run/docker.sock); slow VPN/links exceeding 8 seconds to establish.

Related errors


AI-assisted analysis of jesseduffield/lazydocker@7e7aadc207 (2026-08-15). Data as JSON: /api/errors/6fc00642a767b751. Report an issue: GitHub.