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

  1. Use only the supported keys: target, published, protocol, mode.
  2. For IP binding, note hostip is unsupported for swarm services (see line 116).
  3. Verify field names against `docker service create --help` for your CLI version.
  4. 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

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


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)