jesseduffield/lazydocker · error

create ssh tunnel tmp file: %w

Error message

create ssh tunnel tmp file: %w

What it means

The first step of createDockerHostTunnel creates a temporary directory /tmp/lazydocker-sshtunnel-* to hold the local unix socket that will forward to the remote docker daemon. This error means that os.MkdirTemp-style call failed, with the OS error chained via %w (despite the message saying 'tmp file').

Source

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

func (noopCloser) Close() error { return nil }

type tunneledDockerHost struct {
	socketPath string
	cmd        *exec.Cmd
	oSCommand  CmdKiller
}

var _ io.Closer = (*tunneledDockerHost)(nil)

func (t *tunneledDockerHost) Close() error {
	return t.oSCommand.Kill(t.cmd)
}

func (self *SSHHandler) createDockerHostTunnel(ctx context.Context, remoteHost string) (*tunneledDockerHost, error) {
	socketDir, err := self.tempDir("/tmp", "lazydocker-sshtunnel-")
	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)
	}

View on GitHub (pinned to 7e7aadc207)

Solutions

  1. Free space or fix permissions on /tmp: `df -h /tmp` and `ls -ld /tmp` (should be drwxrwxrwt, owned by root).
  2. If in a container, mount a writable /tmp or run with an adequate tmpfs size.
  3. Clean stale lazydocker-sshtunnel-* directories left by crashed runs: `rm -rf /tmp/lazydocker-sshtunnel-*`.
  4. As a workaround, build the tunnel manually with ssh -L into a writable directory and point DOCKER_HOST at that socket.

Example fix

# before
# /tmp read-only inside container
lazydocker   # create ssh tunnel tmp file: ...: read-only file system

# after (run container with writable tmp)
docker run -v /tmp:/tmp ... lazydocker
# or fix the mount: tmpfs on /tmp with rw
Defensive patterns

Strategy: validation

Validate before calling

if err := checkWritableDir("/tmp"); err != nil {
    return fmt.Errorf("cannot use /tmp for ssh tunnel socket: %w", err)
}
// checkWritableDir: create+remove a probe file in the directory

Prevention

When it happens

Trigger: Starting lazydocker with DOCKER_HOST=ssh://... when /tmp is not writable, the disk/inode pool is exhausted, TMPDIR-related restrictions apply (sandbox, read-only rootfs, seccomp/container restrictions), or the process lacks permission to create directories under /tmp.

Common situations: Running lazydocker inside a container with a read-only or full filesystem; hardened/sandboxed environments (noexec/nodev/nosuid tmp mounts, systemd PrivateTmp restrictions); disk-full servers; unusual setups where /tmp is a small tmpfs that filled up.

Related errors


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