docker/cli · error

scale can only be used with replicated or replicated-job…

Error message

scale can only be used with replicated or replicated-job mode

What it means

Thrown by runServiceScale (cli/command/service/scale.go:108) when the inspected service's Spec.Mode is neither Replicated nor ReplicatedJob. Scaling works by writing to Replicated.Replicas or ReplicatedJob.TotalCompletions; global and global-job modes have no count field to mutate, so the switch statement falls through to its default branch.

Solutions

  1. Recreate the service in a scalable mode if a fixed count is required: `docker service create --mode replicated --replicas N ...`.
  2. For global services, scale horizontally by adding/removing swarm nodes rather than using `docker service scale`.
  3. Inspect the mode before scaling: `docker service inspect --format '{{json .Spec.Mode}}' <svc>` and skip scale for non-replicated modes.

Example fix

// before
docker service scale myservice=5   # myservice is --mode global

// after
docker service inspect --format '{{json .Spec.Mode}}' myservice
# => {"Global":{}}  -> do not scale; scale by adding nodes instead
Defensive patterns

Strategy: validation

Validate before calling

// Before scaling, confirm the service is in a scalable mode.
res, err := apiClient.ServiceInspect(ctx, id, client.ServiceInspectOptions{})
if err != nil { return err }
m := res.Service.Spec.Mode
if m.Replicated == nil && m.ReplicatedJob == nil {
    return fmt.Errorf("service %s is not replicated/replicated-job; cannot scale", id)
}
// safe to scale now

Type guard

// Narrows a swarm.ServiceMode to a scalable count field.
func scalableCount(m *swarm.ServiceMode) (set func(uint64), ok bool) {
	if m.Replicated != nil {
		return func(n uint64) { m.Replicated.Replicas = &n }, true
	}
	if m.ReplicatedJob != nil {
		return func(n uint64) { m.ReplicatedJob.TotalCompletions = &n }, true
	}
	return nil, false
}

Prevention

When it happens

Trigger: Running `docker service scale <svc>=N` against a service created with `--mode global` or `--mode global-job`. The ServiceInspect call succeeds, but neither case in the switch matches, hitting the default that returns this error.

Common situations: Operator forgets a service was deployed globally and scripts a scale call; a Compose file sets `deploy.mode: global` but the pipeline assumes it can scale; migrating a service between modes without recreating it.

Related errors


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

Appendix: source

Thrown at cli/command/service/scale.go:108

		}
	}
	return errors.Join(errs...)
}

func runServiceScale(ctx context.Context, apiClient client.ServiceAPIClient, serviceID string, scale uint64) (warnings []string, _ error) {
	res, err := apiClient.ServiceInspect(ctx, serviceID, client.ServiceInspectOptions{})
	if err != nil {
		return nil, err
	}

	serviceMode := &res.Service.Spec.Mode
	switch {
	case serviceMode.Replicated != nil:
		serviceMode.Replicated.Replicas = &scale
	case serviceMode.ReplicatedJob != nil:
		serviceMode.ReplicatedJob.TotalCompletions = &scale
	default:
		return nil, errors.New("scale can only be used with replicated or replicated-job mode")
	}

	response, err := apiClient.ServiceUpdate(ctx, res.Service.ID, client.ServiceUpdateOptions{
		Version: res.Service.Version,
		Spec:    res.Service.Spec,
	})
	if err != nil {
		return nil, err
	}
	return response.Warnings, nil
}

// completeScaleArgs returns a completion function for the args of the scale command.
// It completes service names followed by "=", suppressing the trailing space.
func completeScaleArgs(dockerCli command.Cli) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
	return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
		// reuse the existing logic for configurable completion of service names and IDs.
		completions, directive := completeServiceNames(dockerCli)(cmd, args, toComplete)

View on GitHub (pinned to 4f84911bfe)