docker/cli · error

incorrect scheme:

Error message

incorrect scheme: 

What it means

Returned by newSpec when the URL has a scheme but it is not 'ssh' (the message appends the offending scheme, e.g. 'incorrect scheme: tcp'). The SSH connection helper is invoked for non-socket, non-tcp hosts but only knows how to build ssh command lines, so any other scheme is rejected.

Source

Thrown at cli/connhelper/ssh/ssh.go:46

// an error if the URL is using the wrong scheme, contains fragments,
// query-parameters, or contains a password.
func NewSpec(sshURL *url.URL) (*Spec, error) {
	s, err := newSpec(sshURL)
	if err != nil {
		return nil, fmt.Errorf("invalid SSH URL: %w", err)
	}
	return s, nil
}

func newSpec(u *url.URL) (*Spec, error) {
	if u == nil {
		return nil, errors.New("URL is nil")
	}
	if u.Scheme == "" {
		return nil, errors.New("no scheme provided")
	}
	if u.Scheme != "ssh" {
		return nil, errors.New("incorrect scheme: " + u.Scheme)
	}

	var sp Spec

	if u.User != nil {
		sp.User = u.User.Username()
		if _, ok := u.User.Password(); ok {
			return nil, errors.New("plain-text password is not supported")
		}
	}
	sp.Host = u.Hostname()
	if sp.Host == "" {
		return nil, errors.New("hostname is empty")
	}
	sp.Port = u.Port()
	sp.Path = u.Path
	if u.RawQuery != "" {
		return nil, fmt.Errorf("query parameters are not allowed: %q", u.RawQuery)

View on GitHub (pinned to 4f84911bfe)

Solutions

  1. Use the 'ssh://' scheme for remote Docker access over SSH.
  2. For TCP, set DOCKER_HOST=tcp://host:2375 (and configure TLS separately).
  3. Verify the URL scheme matches the intended transport before passing it to ssh.ParseURL.

Example fix

# before
DOCKER_HOST=tcp://remote-host
# after (for SSH transport)
DOCKER_HOST=ssh://user@remote-host
Defensive patterns

Strategy: type-guard

Validate before calling

const allowedSchemes = map[string]bool{"ssh": true, "tcp": true, "unix": true, "npipe": true, "fd": true}
if u, err := url.Parse(host); err == nil && !allowedSchemes[u.Scheme] {
    return fmt.Errorf("unsupported scheme %q", u.Scheme)
}

Type guard

func isSSHURL(s string) bool {
    u, err := url.Parse(s)
    return err == nil && u.Scheme == "ssh"
}

Prevention

When it happens

Trigger: The SSH helper receives a URL like 'tcp://host', 'http://host', or 'fd://host'. This happens when DOCKER_HOST is set to a scheme the helper does not handle but the dispatcher routed it here, or when explicitly calling ssh.NewSpec with a non-ssh URL.

Common situations: A user expects the helper to fall back to TCP but it refuses. Passing an http(s) endpoint into the SSH parser by mistake.

Related errors


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