docker/cli · error
invalid field key
Error message
invalid field key: %s
What it means
Thrown by PortOpt.Set (port.go:96) when a field key in long syntax is not one of target, published, protocol, mode. Any unrecognized key (typo or unsupported) reaches the switch default and is reported. Note the key is already lowercased at line 54, so case is not the issue.
Solutions
- Use only the supported keys: target, published, protocol, mode.
- For IP binding, note hostip is unsupported for swarm services (see line 116).
- Verify field names against `docker service create --help` for your CLI version.
- Check for typos; keys are case-insensitive but name-strict.
Example fix
// before --publish port=80,host=8080 // after --publish target=80,published=8080
Defensive patterns
Strategy: validation
Validate before calling
// Allowlist long-syntax publish keys.
var portKeys = map[string]bool{"target": true, "published": true, "protocol": true, "mode": true}
for _, f := range strings.Split(pubVal, ",") {
k, _, _ := strings.Cut(strings.ToLower(strings.TrimSpace(f)), "=")
if !portKeys[k] { return fmt.Errorf("unknown publish key %q", k) }
} Prevention
- Use target (not 'port') and published (not 'host').
- IP binding is unsupported in swarm long syntax (and hostip in short).
- Verify keys against your CLI version's help.
- Treat unknown-key errors as a spec/version mismatch.
When it happens
Trigger: Passing `--publish port=80` (should be `target=80`), `host=8080` (should be `published`), `ip=127.0.0.1`, or any invented field. The switch at line 58 has no matching case, so line 96 fires with the offending key.
Common situations: Using generic names like 'port'/'host' instead of 'target'/'published', trying to bind an IP (not supported in long syntax — use short syntax or it's rejected), or version skew.
Related errors
- invalid field
- invalid protocol value
- invalid publish mode value
- invalid target port ( ): value must be an integer
- invalid published port
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/dc09cffdc471780d.
Report an issue: GitHub.
Appendix: source
Thrown at opts/swarmopts/port.go:96
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.Err
}
return fmt.Errorf("invalid published port (%s): value must be an integer: %w", val, err)
}
pConfig.PublishedPort = uint32(pPort)
default:
return fmt.Errorf("invalid field key: %s", key)
}
}
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 {View on GitHub (pinned to 4f84911bfe)