docker/cli · error
bad format for add-host
Error message
bad format for add-host: %q
What it means
Returned by ValidateExtraHost (opts/hosts.go:174) when a `--add-host` value cannot be split into hostname:IP (or hostname=IP). The function first tries '=' then falls back to the first ':'; this error fires when neither split succeeds, the hostname (key) is empty, or the hostname itself contains a colon. It guards the well-known `name:ip` extra-hosts format that the daemon later writes into /etc/hosts.
Solutions
- Format as name:ip, e.g. my-host:127.0.0.1.
- For IPv6 use name:::1, name=::1, or name=[::1] (all accepted).
- Use the literal host-gateway as the value to skip IP validation: my-host:host-gateway.
- Ensure the name part has no colon and is non-empty.
Example fix
// before
v, err := opts.ValidateExtraHost("myhost")
// after
v, err := opts.ValidateExtraHost("myhost:127.0.0.1") Defensive patterns
Strategy: validation
Validate before calling
// validateExtraHostShape checks the name:ip / name=ip shape before calling ValidateExtraHost.
func validateExtraHostShape(val string) error {
k, _, hasEq := strings.Cut(val, "=")
if !hasEq {
k, _, hasEq = strings.Cut(val, ":")
}
if !hasEq || strings.TrimSpace(k) == "" || strings.Contains(k, ":") {
return fmt.Errorf("expected name:ip or name=ip, got %q", val)
}
return nil
} Try / catch
for _, h := range cfg.AddHosts {
if _, err := opts.ValidateExtraHost(h); err != nil {
return fmt.Errorf("bad add-host %q: %w", h, err)
}
} Prevention
- Use name:ip consistently; reserve name=ip for IPv6 to avoid colon ambiguity.
- Validate add-host entries in your config loader before they reach the daemon request.
- Reject entries whose name contains a colon at config-parse time.
When it happens
Trigger: Calling ValidateExtraHost with a value that has no '=' and no ':', an empty hostname half (e.g. `:127.0.0.1`), or a hostname containing ':' (which would confuse the API server's colon-based split). ListOpts using ValidateExtraHost as its validator hits this on each Set().
Common situations: Forgetting the IP (`myhost`), using a comma or space as separator (`myhost,127.0.0.1`), pasting an IPv6 literal as the name side, or trailing separator (`myhost:`).
Related errors
- invalid IP address in add-host
- invalid option ' ' in ' ': option should not have whitespace
- conflicting options: cannot specify both --host and…
- specify only one -H
- invalid device specification
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/2a51253a20968b07.
Report an issue: GitHub.
Appendix: source
Thrown at opts/hosts.go:174
// my-hostname=::1
// my-hostname:[::1]
//
// For compatibility with the API server, this function normalises the given
// argument to use the ':' separator and strip square brackets enclosing the
// address.
func ValidateExtraHost(val string) (string, error) {
k, v, ok := strings.Cut(val, "=")
if !ok {
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
k, v, ok = strings.Cut(val, ":")
}
// Check that a hostname was given, and that it doesn't contain a ":". (Colon
// isn't allowed in a hostname, along with many other characters. It's
// special-cased here because the API server doesn't know about '=' separators in
// '--add-host'. So, it'll split at the first colon and generate a strange error
// message.)
if !ok || k == "" || strings.Contains(k, ":") {
return "", fmt.Errorf("bad format for add-host: %q", val)
}
// Skip IPaddr validation for "host-gateway" string
if v != hostGatewayName {
// If the address is enclosed in square brackets, extract it (for IPv6, but
// permit it for IPv4 as well; we don't know the address family here, but it's
// unambiguous).
if len(v) > 2 && v[0] == '[' && v[len(v)-1] == ']' {
v = v[1 : len(v)-1]
}
// ValidateIPAddress returns the address in canonical form (for example,
// 0:0:0:0:0:0:0:1 -> ::1). But, stick with the original form, to avoid
// surprising a user who's expecting to see the address they supplied in the
// output of 'docker inspect' or '/etc/hosts'.
if _, err := ValidateIPAddress(v); err != nil {
return "", fmt.Errorf("invalid IP address in add-host: %q", v)
}
}
// This result is passed directly to the API, the daemon doesn't accept the '='View on GitHub (pinned to 4f84911bfe)