{"record":{"id":"bd02e8586a5a2683","repo":"docker/cli","slug":"invalid-ip-address-in-add-host-q","errorCode":null,"errorMessage":"invalid IP address in add-host: %q","messagePattern":"invalid IP address in add-host: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"opts/hosts.go","lineNumber":189,"sourceCode":"\t// '--add-host'. So, it'll split at the first colon and generate a strange error\n\t// message.)\n\tif !ok || k == \"\" || strings.Contains(k, \":\") {\n\t\treturn \"\", fmt.Errorf(\"bad format for add-host: %q\", val)\n\t}\n\t// Skip IPaddr validation for \"host-gateway\" string\n\tif v != hostGatewayName {\n\t\t// If the address is enclosed in square brackets, extract it (for IPv6, but\n\t\t// permit it for IPv4 as well; we don't know the address family here, but it's\n\t\t// unambiguous).\n\t\tif len(v) > 2 && v[0] == '[' && v[len(v)-1] == ']' {\n\t\t\tv = v[1 : len(v)-1]\n\t\t}\n\t\t// ValidateIPAddress returns the address in canonical form (for example,\n\t\t// 0:0:0:0:0:0:0:1 -> ::1). But, stick with the original form, to avoid\n\t\t// surprising a user who's expecting to see the address they supplied in the\n\t\t// output of 'docker inspect' or '/etc/hosts'.\n\t\tif _, err := ValidateIPAddress(v); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"invalid IP address in add-host: %q\", v)\n\t\t}\n\t}\n\t// This result is passed directly to the API, the daemon doesn't accept the '='\n\t// separator or an address enclosed in brackets. So, construct something it can\n\t// understand.\n\treturn k + \":\" + v, nil\n}\n","sourceCodeStart":171,"sourceCodeEnd":197,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/opts/hosts.go#L171-L197","documentation":"Returned by ValidateExtraHost (opts/hosts.go:189) when the IP half of a `--add-host` entry fails ValidateIPAddress. After stripping optional square brackets, the value must parse as an IPv4/IPv6 address via net.ParseIP, unless it is the exact string `host-gateway` (which is special-cased and skips validation). This catches malformed addresses before they reach the daemon.","triggerScenarios":"Calling ValidateExtraHost where the value side (after `:` or `=` and bracket stripping) is not a valid IP and is not `host-gateway`, e.g. `myhost:127.0.0`, `myhost:999.999.999.999`, `myhost:example.com`, or `myhost:not-an-ip`.","commonSituations":"Typing a hostname instead of an IP on the value side, truncated IPv4, wrong IPv6 syntax, or assuming DNS names are accepted (they are not — only IPs or host-gateway).","solutions":["Use a valid IPv4 (myhost:127.0.0.1) or IPv6 (myhost:::1 / myhost=[::1]).","If you meant the host's gateway IP, use the literal: myhost:host-gateway.","Resolve any DNS name to an IP yourself before constructing the entry; the parser does not resolve names.","Check for stray brackets/whitespace — only fully-wrapped [addr] is unwrapped, partial brackets are left intact and fail."],"exampleFix":"// before\nv, err := opts.ValidateExtraHost(\"db:db.internal\")\n\n// after\nv, err := opts.ValidateExtraHost(\"db:10.0.0.5\")","handlingStrategy":"validation","validationCode":"// resolveAddHostIP returns the IP to store, or an error, before ValidateExtraHost.\nfunc resolveAddHostIP(value string) (string, error) {\n    if value == \"host-gateway\" {\n        return value, nil\n    }\n    v := strings.Trim(value, \"[]\")\n    if ip := net.ParseIP(strings.TrimSpace(v)); ip == nil {\n        return \"\", fmt.Errorf(\"not a valid IP: %q\", value)\n    }\n    return v, nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := opts.ValidateExtraHost(entry); err != nil {\n    return fmt.Errorf(\"invalid extra host %q: %w\", entry, err)\n}","preventionTips":["Resolve DNS names to IPs before building add-host strings.","Use host-gateway literally when you want the host gateway.","Strip brackets from IPv6 yourself only if you bypass ValidateExtraHost."],"tags":["networking","host","docker","add-host","ip-address","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}