docker/cli · error

replicas-max-per-node can only be used with replicated or…

Error message

replicas-max-per-node can only be used with replicated or replicated-job mode

What it means

In `ToServiceMode()`, the `--mode global` case at opts.go:633-634 also checks `--replicas-max-per-node` (`options.maxReplicas > 0`). Global services run one task per node by definition, so capping tasks per node is not applicable. This fires when the `--replicas-max-per-node` flag is set to a value greater than zero alongside `--mode global`.

Solutions

  1. Remove `--replicas-max-per-node` when using `--mode global`
  2. Switch to `--mode replicated` or `--mode replicated-job` to use this flag

Example fix

# before
docker service create --mode global --replicas-max-per-node 2 --image nginx web
# error: replicas-max-per-node can only be used with replicated or replicated-job mode

# after
docker service create --mode global --image nginx web
Defensive patterns

Strategy: validation

Validate before calling

// Validate maxReplicas with mode
func validateMaxReplicasWithMode(mode string, maxReplicas uint64) error {
    if (mode == "global" || mode == "global-job") && maxReplicas > 0 {
        return errors.New("replicas-max-per-node can only be used with replicated or replicated-job mode")
    }
    return nil
}

Prevention

When it happens

Trigger: Running `docker service create --mode global --replicas-max-per-node 2 --image nginx web`. The `--replicas-max-per-node` flag maps to `options.maxReplicas` (line 915), which defaults to 0 (unlimited); any non-zero value with global mode triggers this error.

Common situations: A developer migrates from replicated mode and leaves the `--replicas-max-per-node` flag in place, or sets it globally in a script for all services.

Related errors


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

Appendix: source

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

		dnsSearch:       opts.NewListOpts(opts.ValidateDNSSearch),
		hosts:           opts.NewListOpts(opts.ValidateExtraHost),
		sysctls:         opts.NewListOpts(nil),
		capAdd:          opts.NewListOpts(nil),
		capDrop:         opts.NewListOpts(nil),
		ulimits:         *opts.NewUlimitOpt(nil),
	}
}

func (options *serviceOptions) ToServiceMode() (swarm.ServiceMode, error) {
	serviceMode := swarm.ServiceMode{}
	switch options.mode {
	case "global":
		if options.replicas.Value() != nil {
			return serviceMode, errors.New("replicas can only be used with replicated or replicated-job mode")
		}

		if options.maxReplicas > 0 {
			return serviceMode, errors.New("replicas-max-per-node can only be used with replicated or replicated-job mode")
		}
		if options.maxConcurrent.Value() != nil {
			return serviceMode, errors.New("max-concurrent can only be used with replicated-job mode")
		}

		serviceMode.Global = &swarm.GlobalService{}
	case "replicated":
		if options.maxConcurrent.Value() != nil {
			return serviceMode, errors.New("max-concurrent can only be used with replicated-job mode")
		}

		serviceMode.Replicated = &swarm.ReplicatedService{
			Replicas: options.replicas.Value(),
		}
	case "replicated-job":
		concurrent := options.maxConcurrent.Value()
		if concurrent == nil {
			concurrent = options.replicas.Value()

View on GitHub (pinned to 4f84911bfe)