wagoodman/dive · error

failed to get docker connection helper: %w

Error message

failed to get docker connection helper: %w

What it means

Returned by engineResolver.fetchArchive (dive/image/docker/engine_resolver.go:84) when the resolved docker host starts with 'ssh:' and connhelper.GetConnectionHelper(host) fails. The connection helper parses the ssh:// DOCKER_HOST URL and prepares a dialer; invalid URLs or an unusable ssh setup make it error, wrapped here with %w.

Source

Thrown at dive/image/docker/engine_resolver.go:84

	return fmt.Errorf("unable to extract from image '%s': %+v", id, err)
}

func (r *engineResolver) fetchArchive(ctx context.Context, id string) (io.ReadCloser, error) {
	var err error
	var dockerClient *client.Client

	host, err := determineDockerHost()
	if err != nil {
		return nil, fmt.Errorf("could not determine docker host: %v", err)
	}
	clientOpts := []client.Opt{client.FromEnv}
	clientOpts = append(clientOpts, client.WithHost(host))

	switch strings.Split(host, ":")[0] {
	case "ssh":
		helper, err := connhelper.GetConnectionHelper(host)
		if err != nil {
			return nil, fmt.Errorf("failed to get docker connection helper: %w", err)
		}
		clientOpts = append(clientOpts, func(c *client.Client) error {
			httpClient := &http.Client{
				Transport: &http.Transport{
					DialContext: helper.Dialer,
				},
			}
			return client.WithHTTPClient(httpClient)(c)
		})

		clientOpts = append(clientOpts, client.WithHost(host))
		clientOpts = append(clientOpts, client.WithDialContext(helper.Dialer))

	default:

		if os.Getenv("DOCKER_TLS_VERIFY") != "" && os.Getenv("DOCKER_CERT_PATH") == "" {
			os.Setenv("DOCKER_CERT_PATH", "~/.docker")
		}

View on GitHub (pinned to d6c691947f)

Solutions

  1. Prove plain ssh works first: ssh -v <user>@<host> docker version - the same connection the helper will make
  2. Fix the DOCKER_HOST format: ssh://user@host:port (note port after host, not ssh://host:22/user)
  3. Ensure a local ssh client exists and keys/agent are available in the environment dive runs in (CI agents often lack the agent socket)
  4. Unwrap the error for the precise cause - %w preserves connhelper's message

Example fix

# before
export DOCKER_HOST=ssh://docker@remote:2375   # 2375 is not an ssh port

# after (ssh on port 2222, remote dockerd via its socket)
export DOCKER_HOST=ssh://docker@remote:2222
ssh -p 2222 docker@remote docker version  # verify before running dive
Defensive patterns

Strategy: validation

Validate before calling

// validate an ssh:// DOCKER_HOST before dive runs
host := os.Getenv("DOCKER_HOST")
if strings.HasPrefix(host, "ssh://") {
    u, err := url.Parse(host)
    if err != nil || u.User == nil && u.Hostname() == "" {
        return fmt.Errorf("invalid DOCKER_HOST %q", host)
    }
    // prove ssh itself works with the same destination:
    if err := exec.Command("ssh", strings.TrimPrefix(host, "ssh://"), "true").Run(); err != nil {
        return fmt.Errorf("ssh to docker host fails: %w", err)
    }
}

Try / catch

reader, err := resolver.Fetch(ctx, id)
if err != nil {
    var helperErr *net.OpError // unwrap chain as needed; connhelper errors are plain fmt.Errorf
    if strings.Contains(err.Error(), "failed to get docker connection helper") {
        return fmt.Errorf("bad DOCKER_HOST=%q; expected ssh://user@host[:port] and a working ssh key", os.Getenv("DOCKER_HOST"))
    }
    return err
}

Prevention

When it happens

Trigger: DOCKER_HOST=ssh://user@bad-host (unresolvable, typo'd scheme content), ssh:// with no user/host, an ssh binary that the helper cannot locate, or key/endpoint forms the helper rejects.

Common situations: Remote docker over SSH where the remote user or port is encoded incorrectly (helper expects ssh://user@host:port form; DOCKER_HOST=ssh://host without keys, or leftover windows-style paths); firewalled or renamed remote hosts after a config was written.

Related errors


AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15). Data as JSON: /api/errors/b7e919d807f89203. Report an issue: GitHub.