docker/cli · error
invalid publish mode value
Error message
invalid publish mode value (%s): must be either '%s' or '%s'
What it means
Thrown by PortOpt.Set (port.go:71) when the `mode` field is neither 'ingress' nor 'host'. Swarm service port publish modes are limited to these two values; the switch over swarm.PortConfigPublishMode(val) matches only PortConfigPublishModeIngress and PortConfigPublishModeHost, so any other string hits the default case.
Solutions
- Use mode=ingress (default, routing mesh) or mode=host (bypass mesh, host-native).
- Double-check spelling: 'ingress' not 'ingres', 'host' not 'hosts'.
- If unsure, omit the mode field to get the default (ingress).
- Remember: these are publish modes, not network drivers.
Example fix
// before --publish target=80,mode=bridge // after --publish target=80,mode=ingress (or mode=host to bypass the routing mesh)
Defensive patterns
Strategy: validation
Validate before calling
// Restrict publish mode to ingress/host.
var okMode = map[string]bool{"ingress": true, "host": true}
if !okMode[strings.ToLower(modeVal)] {
return fmt.Errorf("mode %q must be ingress or host", modeVal)
} Prevention
- Use mode=ingress (routing mesh) or mode=host (no mesh).
- Omit mode to default to ingress.
- Don't conflate publish modes with network drivers.
- Spell 'ingress' fully.
When it happens
Trigger: Passing `--publish target=80,mode=bridge`, `mode=mesh`, `mode=global`, or a typo like `mode=ingres`. swarm.PortConfigPublishMode(val) yields a value not equal to either constant, firing line 71.
Common situations: Confusing swarm publish modes with Docker network drivers (bridge/host as a driver), typos, or assuming 'global' (a service mode) is a publish mode.
Related errors
- invalid field
- invalid protocol value
- invalid target port ( ): value must be an integer
- invalid published port
- invalid field key
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/cad287813df756b0.
Report an issue: GitHub.
Appendix: source
Thrown at opts/swarmopts/port.go:71
// TODO(thaJeztah): these options should not be case-insensitive.
key, val, ok := strings.Cut(strings.ToLower(field), "=")
if !ok || key == "" {
return fmt.Errorf("invalid field: %s", field)
}
switch key {
case portOptProtocol:
switch proto := network.IPProtocol(val); proto {
case network.TCP, network.UDP, network.SCTP:
pConfig.Protocol = proto
default:
return fmt.Errorf("invalid protocol value '%s'", val)
}
case portOptMode:
switch swarm.PortConfigPublishMode(val) {
case swarm.PortConfigPublishModeIngress, swarm.PortConfigPublishModeHost:
pConfig.PublishMode = swarm.PortConfigPublishMode(val)
default:
return fmt.Errorf("invalid publish mode value (%s): must be either '%s' or '%s'", val, swarm.PortConfigPublishModeIngress, swarm.PortConfigPublishModeHost)
}
case portOptTargetPort:
tPort, err := strconv.ParseUint(val, 10, 16)
if err != nil {
var numErr *strconv.NumError
if errors.As(err, &numErr) {
err = numErr.Err
}
return fmt.Errorf("invalid target port (%s): value must be an integer: %w", val, err)
}
pConfig.TargetPort = uint32(tPort)
case portOptPublishedPort:
pPort, err := strconv.ParseUint(val, 10, 16)
if err != nil {
var numErr *strconv.NumError
if errors.As(err, &numErr) {
err = numErr.ErrView on GitHub (pinned to 4f84911bfe)