docker/cli · error
hostip is not supported
Error message
hostip is not supported
What it means
Thrown by PortOpt.Set in the SHORT port syntax path when a parsed port binding carries a non-empty HostIP. Swarm service port configs (--publish in docker service create) do not support binding to a specific host IP; only the long key=value syntax is used for fine control. The error is returned after nat.ParsePortSpecs succeeds but yields a HostIP.
Solutions
- Drop the IP prefix for swarm services: --publish 8080:80.
- If host-mode is intended, use the long syntax with mode=host and omit the IP: published=8080,target=80,mode=host.
- Use docker run (not swarm) if you truly need host-IP port binding.
Example fix
# before docker service create --publish 127.0.0.1:8080:80 nginx # after docker service create --publish 8080:80 nginx
Defensive patterns
Strategy: validation
Validate before calling
// for swarm service ports, reject short syntax with an IP prefix
if regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+:`).MatchString(portSpec) {
return errors.New("host IP is not supported in short swarm publish syntax")
} Try / catch
if err := portOpt.Set(spec); err != nil {
return err
} Prevention
- Do not copy docker run -p IP:host:container bindings into docker service create.
- Use the long publish syntax (published=,target=,mode=) for swarm.
When it happens
Trigger: Using the short syntax with an IP prefix, e.g. --publish 127.0.0.1:8080:80, with docker service create/update.
Common situations: Copying a docker run -p 127.0.0.1:8080:80 binding verbatim into docker service create, expecting the same behavior. Swarm ingress/host-mode publishing does not pin to a host IP via short syntax.
Related errors
- source is required
- invalid field in secret request
- source is required
- error reading from STDIN: data is empty
- config file is required
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/4a0a37c91c516636.
Report an issue: GitHub.
Appendix: source
Thrown at opts/swarmopts/port.go:116
}
if pConfig.TargetPort == 0 {
return fmt.Errorf("missing mandatory field '%s'", portOptTargetPort)
}
p.ports = append(p.ports, pConfig)
} else {
// short syntax ([ip:]public:private[/proto])
//
// TODO(thaJeztah): we need an equivalent that handles the "ip-address" part without depending on the nat package.
ports, portBindingMap, err := nat.ParsePortSpecs([]string{value})
if err != nil {
return err
}
for _, portBindings := range portBindingMap {
for _, portBinding := range portBindings {
if portBinding.HostIP != "" {
return errors.New("hostip is not supported")
}
}
}
var portConfigs []swarm.PortConfig
for port := range ports {
portProto, err := network.ParsePort(string(port))
if err != nil {
return err
}
portConfig, err := ConvertPortToPortConfig(portProto, portBindingMap)
if err != nil {
return err
}
portConfigs = append(portConfigs, portConfig...)
}
p.ports = append(p.ports, portConfigs...)
}View on GitHub (pinned to 4f84911bfe)