{"id":"e9c24dd826e2a64d","repo":"docker/cli","slug":"the-raw-stream-connection-does-not-implement-halfc","errorCode":null,"errorMessage":"the raw stream connection does not implement halfCloser","messagePattern":"the raw stream connection does not implement halfCloser","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/system/dial_stdio.go","lineNumber":50,"sourceCode":"func runDialStdio(ctx context.Context, dockerCli command.Cli) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tdialer := dockerCli.Client().Dialer()\n\tconn, err := dialer(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to open the raw stream connection: %w\", err)\n\t}\n\tdefer conn.Close()\n\n\tvar connHalfCloser halfCloser\n\tswitch t := conn.(type) {\n\tcase halfCloser:\n\t\tconnHalfCloser = t\n\tcase halfReadWriteCloser:\n\t\tconnHalfCloser = &nopCloseReader{t}\n\tdefault:\n\t\treturn errors.New(\"the raw stream connection does not implement halfCloser\")\n\t}\n\n\tstdin2conn := make(chan error, 1)\n\tconn2stdout := make(chan error, 1)\n\tgo func() {\n\t\tstdin2conn <- copier(connHalfCloser, &halfReadCloserWrapper{os.Stdin}, \"stdin to stream\")\n\t}()\n\tgo func() {\n\t\tconn2stdout <- copier(&halfWriteCloserWrapper{os.Stdout}, connHalfCloser, \"stream to stdout\")\n\t}()\n\tselect {\n\tcase err = <-stdin2conn:\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// wait for stdout\n\t\terr = <-conn2stdout\n\tcase err = <-conn2stdout:","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/system/dial_stdio.go#L32-L68","documentation":"Raised by `docker system dial-stdio` when the connection returned by the API client's Dialer does not support half-close semantics (CloseRead/CloseWrite) and is not even a half-read/write-closer the CLI can wrap. dial-stdio proxies stdin/stdout to the raw Docker daemon stream and needs to close each direction independently, so a connection type without those methods cannot be used.","triggerScenarios":"Running `docker system dial-stdio` when dockerCli.Client().Dialer() yields a net.Conn type that implements neither the halfCloser interface (CloseRead+CloseWrite) nor halfReadWriteCloser — e.g. certain tunneled, proxied, or custom transport connections (some TLS or exotic connection helpers) instead of a plain *net.TCPConn or *net.UnixConn.","commonSituations":"Using dial-stdio (often invoked implicitly by `docker -H ssh://...` or buildx/BuildKit clients) through a connection helper or proxy whose transport doesn't expose half-close; custom DOCKER_HOST transports; older/newer client-transport combinations changing the concrete conn type.","solutions":["Connect over a transport that supports half-close: unix socket (unix:///var/run/docker.sock) or plain tcp:// instead of a wrapped/proxied transport.","If using ssh:// or a connection helper, update the docker CLI — half-close handling for wrapped connections has improved across versions.","As a workaround, avoid dial-stdio by pointing the client directly at the daemon endpoint (set DOCKER_HOST) rather than tunneling through the CLI."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker-cli","dial-stdio","networking","transport"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}