docker/cli · error

placement preference must be of the format

Error message

placement preference must be of the format "<strategy>=<arg>"

What it means

The `--placement-pref` flag for `docker service create/update` expects values in the format `<strategy>=<argument>`. The `placementPrefOpts.Set` method at opts.go:99-103 uses `strings.Cut(value, "=")` to split the input. This error fires when there is no `=` separator at all (`ok == false`) or the strategy portion before `=` is empty. Currently only the "spread" strategy is supported (checked at line 104), but the format error is about the structural requirement, not the strategy choice.

Solutions

  1. Use the exact format: `--placement-pref spread=<label-descriptor>`, e.g., `--placement-pref spread=node.labels.zone`
  2. Check that the strategy is "spread" (the only currently supported value) and that a non-empty label follows the `=`

Example fix

# before
docker service create --placement-pref "spread" --image nginx web
# error: placement preference must be of the format "<strategy>=<arg>"

# before (also wrong)
docker service create --placement-pref "node.labels.zone" --image nginx web

# after
docker service create --placement-pref "spread=node.labels.zone" --image nginx web
Defensive patterns

Strategy: validation

Validate before calling

// Validate placement preference before calling Set
func validatePlacementPref(value string) error {
    strategy, arg, ok := strings.Cut(value, "=")
    if !ok || strategy == "" {
        return fmt.Errorf(`placement preference must be of the format "<strategy>=<arg>"`)
    }
    if strategy != "spread" {
        return fmt.Errorf("unsupported placement preference %s (only spread is supported)", strategy)
    }
    if arg == "" {
        return errors.New("placement preference argument cannot be empty")
    }
    return nil
}

Prevention

When it happens

Trigger: Passing `--placement-pref spread` (missing `=label`), `--placement-pref node.labels.zone` (missing strategy prefix entirely), or `--placement-pref =node.labels.zone` (empty strategy before `=`). Correct form: `--placement-pref spread=node.labels.zone`.

Common situations: A developer reads the help text and forgets the `=` separator, or mistakenly uses a space instead of `=`. Also common when copy-pasting placement constraint syntax (`node.labels.zone == us-east`) into placement-pref.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/338a1038e61c566c. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/service/opts.go:102

type placementPrefOpts struct {
	prefs   []swarm.PlacementPreference
	strings []string
}

func (o *placementPrefOpts) String() string {
	if len(o.strings) == 0 {
		return ""
	}
	return fmt.Sprintf("%v", o.strings)
}

// Set validates the input value and adds it to the internal slices.
// Note: in the future strategies other than "spread", may be supported,
// as well as additional comma-separated options.
func (o *placementPrefOpts) Set(value string) error {
	strategy, arg, ok := strings.Cut(value, "=")
	if !ok || strategy == "" {
		return errors.New(`placement preference must be of the format "<strategy>=<arg>"`)
	}
	if strategy != "spread" {
		return fmt.Errorf("unsupported placement preference %s (only spread is supported)", strategy)
	}

	o.prefs = append(o.prefs, swarm.PlacementPreference{
		Spread: &swarm.SpreadOver{
			SpreadDescriptor: arg,
		},
	})
	o.strings = append(o.strings, value)
	return nil
}

// Type returns a string name for this Option type
func (*placementPrefOpts) Type() string {
	return "pref"
}

View on GitHub (pinned to 4f84911bfe)