{"record":{"id":"3ab6be90ea47e208","repo":"docker/cli","slug":"ssh-host-connection-is-not-valid-w","errorCode":null,"errorMessage":"ssh host connection is not valid: %w","messagePattern":"ssh host connection is not valid: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/connhelper/connhelper.go","lineNumber":50,"sourceCode":"\n// GetConnectionHelperWithSSHOpts returns Docker-specific connection helper for\n// the given URL, and accepts additional options for ssh connections. It returns\n// nil without error when no helper is registered for the scheme.\n//\n// Requires Docker 18.09 or later on the remote host.\nfunc GetConnectionHelperWithSSHOpts(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {\n\treturn getConnectionHelper(daemonURL, sshFlags)\n}\n\nfunc getConnectionHelper(daemonURL string, sshFlags []string) (*ConnectionHelper, error) {\n\tu, err := url.Parse(daemonURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif u.Scheme == \"ssh\" {\n\t\tsp, err := ssh.NewSpec(u)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"ssh host connection is not valid: %w\", err)\n\t\t}\n\t\tsshFlags = addSSHTimeout(sshFlags)\n\t\tsshFlags = disablePseudoTerminalAllocation(sshFlags)\n\n\t\tremoteCommand := []string{\"docker\", \"system\", \"dial-stdio\"}\n\t\tsocketPath := sp.Path\n\t\tif strings.Trim(sp.Path, \"/\") != \"\" {\n\t\t\tremoteCommand = []string{\"docker\", \"--host=unix://\" + socketPath, \"system\", \"dial-stdio\"}\n\t\t}\n\t\tsshArgs, err := sp.Command(sshFlags, remoteCommand...)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &ConnectionHelper{\n\t\t\tDialer: func(ctx context.Context, network, addr string) (net.Conn, error) {\n\t\t\t\treturn commandconn.New(ctx, \"ssh\", sshArgs...)\n\t\t\t},\n\t\t\tHost: \"http://docker.example.com\",","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/connhelper/connhelper.go#L32-L68","documentation":"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.).","triggerScenarios":"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>`.","commonSituations":"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.","solutions":["Read the wrapped inner error to identify the exact disallowed element.","Strip query parameters and fragments from the ssh URL; DOCKER_HOST ssh URLs only support user@host[:port][/socket].","Never embed a password in the URL — use an ssh key or agent instead.","Ensure the hostname is present and the scheme is exactly `ssh`."],"exampleFix":"# before\nexport DOCKER_HOST='ssh://user:pass@host:22?strict=no#frag'\n# after — bare user@host[:port][/socket]\nexport DOCKER_HOST='ssh://user@host:22/var/run/docker.sock'","handlingStrategy":"validation","validationCode":"// Validate the ssh URL shape before passing to GetConnectionHelper.\nu, err := url.Parse(daemonURL)\nif err != nil || u.Scheme != \"ssh\" || u.Hostname() == \"\" || u.RawQuery != \"\" || u.Fragment != \"\" {\n    return errors.New(\"invalid DOCKER_HOST ssh URL\")\n}","typeGuard":null,"tryCatchPattern":"helper, err := connhelper.GetConnectionHelper(daemonURL)\nif err != nil {\n    return fmt.Errorf(\"invalid docker host URL: %w\", err)\n}","preventionTips":["Keep DOCKER_HOST ssh URLs to the form `ssh://[user@]host[:port][/socket]`.","Never embed passwords, query params, or fragments in the URL.","Set ssh options in ~/.ssh/config instead."],"tags":["connhelper","ssh","docker-host","url-validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}