docker/cli · error

ssh host connection is not valid

Error message

ssh host connection is not valid: %w

What it means

Top-level wrapper produced by getConnectionHelper (connhelper.go:47-50) when the DOCKER_HOST URL scheme is `ssh` but ssh.NewSpec fails to build a valid Spec from the parsed URL. The inner error details the precise reason (wrong scheme, empty host, query/fragment present, password in URL, etc.).

Solutions

  1. Read the wrapped inner error to identify the exact disallowed element.
  2. Strip query parameters and fragments from the ssh URL; DOCKER_HOST ssh URLs only support user@host[:port][/socket].
  3. Never embed a password in the URL — use an ssh key or agent instead.
  4. Ensure the hostname is present and the scheme is exactly `ssh`.

Example fix

# before
export DOCKER_HOST='ssh://user:pass@host:22?strict=no#frag'
# after — bare user@host[:port][/socket]
export DOCKER_HOST='ssh://user@host:22/var/run/docker.sock'
Defensive patterns

Strategy: validation

Validate before calling

// Validate the ssh URL shape before passing to GetConnectionHelper.
u, err := url.Parse(daemonURL)
if err != nil || u.Scheme != "ssh" || u.Hostname() == "" || u.RawQuery != "" || u.Fragment != "" {
    return errors.New("invalid DOCKER_HOST ssh URL")
}

Try / catch

helper, err := connhelper.GetConnectionHelper(daemonURL)
if err != nil {
    return fmt.Errorf("invalid docker host URL: %w", err)
}

Prevention

When it happens

Trigger: GetConnectionHelper / GetConnectionHelperWithSSHOpts is called with a daemonURL whose scheme is `ssh`; url.Parse succeeds but ssh.NewSpec(u) returns an error (delegating to newSpec validation). The error is wrapped as `ssh host connection is not valid: <inner>`.

Common situations: DOCKER_HOST is set to an ssh URL with a disallowed component: a query string (`?x=1`), a fragment (`#top`), an embedded password (`ssh://user:pass@host`), or an empty hostname. Also when the scheme is missing or misspelled so url.Parse misinterprets the host.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/3ab6be90ea47e208. Report an issue: GitHub.

Appendix: source

Thrown at cli/connhelper/connhelper.go:50

// GetConnectionHelperWithSSHOpts returns Docker-specific connection helper for
// the given URL, and accepts additional options for ssh connections. It returns
// nil without error when no helper is registered for the scheme.
//
// Requires Docker 18.09 or later on the remote host.
func GetConnectionHelperWithSSHOpts(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {
	return getConnectionHelper(daemonURL, sshFlags)
}

func getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {
	u, err := url.Parse(daemonURL)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "ssh" {
		sp, err := ssh.NewSpec(u)
		if err != nil {
			return nil, fmt.Errorf("ssh host connection is not valid: %w", err)
		}
		sshFlags = addSSHTimeout(sshFlags)
		sshFlags = disablePseudoTerminalAllocation(sshFlags)

		remoteCommand := []string{"docker", "system", "dial-stdio"}
		socketPath := sp.Path
		if strings.Trim(sp.Path, "/") != "" {
			remoteCommand = []string{"docker", "--host=unix://" + socketPath, "system", "dial-stdio"}
		}
		sshArgs, err := sp.Command(sshFlags, remoteCommand...)
		if err != nil {
			return nil, err
		}
		return &ConnectionHelper{
			Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
				return commandconn.New(ctx, "ssh", sshArgs...)
			},
			Host: "http://docker.example.com",

View on GitHub (pinned to 4f84911bfe)