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
- Use the exact format: `--placement-pref spread=<label-descriptor>`, e.g., `--placement-pref spread=node.labels.zone`
- 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
- Always use the spread=<label> format — never omit the = separator
- Validate placement preference strings in deployment scripts before passing to docker service create/update
- Remember that only 'spread' is currently supported as a strategy
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
- replicas can only be used with replicated or replicated-job…
- replicas-max-per-node can only be used with replicated or…
- max-concurrent can only be used with replicated-job mode
- update and rollback configuration is not supported for jobs
- invalid credential spec: value must be prefixed with…
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)