{"record":{"id":"81a5bf1163fad978","repo":"docker/cli","slug":"invalid-proto-expected-tcp-s","errorCode":null,"errorMessage":"invalid proto, expected tcp: %s","messagePattern":"invalid proto, expected tcp: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"opts/hosts.go","lineNumber":105,"sourceCode":"\t}\n\tif addr == \"\" {\n\t\taddr = defaultAddr\n\t}\n\treturn fmt.Sprintf(\"%s://%s\", proto, addr), nil\n}\n\n// ParseTCPAddr parses and validates that the specified address is a valid TCP\n// address. It returns a formatted TCP address, either using the address parsed\n// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.\n// tryAddr is expected to have already been Trim()'d\n// defaultAddr must be in the full `tcp://host:port` form\nfunc ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {\n\tif tryAddr == \"\" || tryAddr == \"tcp://\" {\n\t\treturn defaultAddr, nil\n\t}\n\taddr := strings.TrimPrefix(tryAddr, \"tcp://\")\n\tif strings.Contains(addr, \"://\") || addr == \"\" {\n\t\treturn \"\", fmt.Errorf(\"invalid proto, expected tcp: %s\", tryAddr)\n\t}\n\n\tdefaultAddr = strings.TrimPrefix(defaultAddr, \"tcp://\")\n\tdefaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\t// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but\n\t// not 1.4. See https://github.com/golang/go/issues/12200 and\n\t// https://github.com/golang/go/issues/6530.\n\tif strings.HasSuffix(addr, \"]:\") {\n\t\taddr += defaultPort\n\t}\n\n\tu, err := url.Parse(\"tcp://\" + addr)\n\tif err != nil {\n\t\treturn \"\", err\n\t}","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/opts/hosts.go#L87-L123","documentation":"ParseTCPAddr rejects a tcp address that, after stripping the tcp:// prefix, still contains '://' (a nested scheme) or is empty in a way that is not the special-case bare 'tcp://'. It enforces that exactly one tcp scheme is present and that there is a usable remainder.","triggerScenarios":"-H tcp:// with a nested scheme (tcp://unix://x) or a value that reduces to empty after the prefix in an unexpected form, e.g. tcp:// followed by another scheme token.","commonSituations":"Mixing protocols in one -H value; malformed -H from templating; accidentally prefixing an already-prefixed address.","solutions":["Use a single tcp scheme: tcp://host:port.","Remove any nested '://' from the address.","For the default port, use tcp://host or tcp://:2375 rather than nesting.","Validate the address contains exactly one '://' before ParseTCPAddr."],"exampleFix":"# before\ndocker -H tcp://unix:///var/run/docker.sock ps\n\n# after\ndocker -H tcp://127.0.0.1:2375 ps","handlingStrategy":"validation","validationCode":"// Ensure a tcp address has exactly one tcp scheme and a usable remainder.\nfunc validTCPHost(s string) error {\n    if strings.Count(s, \"://\") != 1 || !strings.HasPrefix(s, \"tcp://\") {\n        return fmt.Errorf(\"expected a single tcp:// scheme in %q\", s)\n    }\n    if strings.TrimPrefix(s, \"tcp://\") == \"\" {\n        return fmt.Errorf(\"empty tcp address in %q\", s)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use exactly one tcp:// scheme per -H value.","Do not nest schemes; switch protocols with separate -H flags.","Validate the address shape before passing to ParseTCPAddr."],"tags":["docker","daemon","host","parsing","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}