docker/cli · error
no replica count
Error message
no replica count
What it means
In `replicatedProgressUpdater.update()` (progress.go:294-296), the method re-checks that `service.Spec.Mode.Replicated` and `service.Spec.Mode.Replicated.Replicas` are non-nil. The updater was initialized in `initializeUpdater()` (line 235) only when both were non-nil, but `ServiceProgress` re-inspects the service on every loop iteration (line 93). If between iterations the service was updated to remove its replica count (e.g., mode changed to global), this re-check fails and returns the error. This is a race condition between progress monitoring and a concurrent service update.
Solutions
- Avoid modifying a service's mode while creation progress monitoring is running
- Use `--detach` when creating the service if concurrent modifications are expected
- Re-run `docker service ps <service>` to check status after the conflicting update completes
Example fix
# problematic: two concurrent operations docker service create --name web --mode replicated --replicas 3 --image nginx & # simultaneously in another terminal: docker service update --mode global web # triggers the race # fix: use --detach to avoid blocking progress monitoring docker service create --detach --name web --mode replicated --replicas 3 --image nginx
Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling ServiceProgress, ensure the service has a stable mode
func hasStableReplicaCount(ctx context.Context, c client.APIClient, svcID string) bool {
res, err := c.ServiceInspect(ctx, svcID, client.ServiceInspectOptions{})
if err != nil {
return false
}
return res.Service.Spec.Mode.Replicated != nil &&
res.Service.Spec.Mode.Replicated.Replicas != nil
} Try / catch
// Handle the race condition gracefully
err := progress.ServiceProgress(ctx, apiClient, svcID, progressWriter)
if err != nil && strings.Contains(err.Error(), "no replica count") {
// Service mode likely changed concurrently; retry once or use --detach
log.Printf("service %s mode changed during progress monitoring", svcID)
} Prevention
- Avoid modifying a service's mode while progress monitoring is active
- Use --detach for service creation if concurrent modifications are expected
- Treat 'no replica count' as a transient race condition, not a permanent failure
When it happens
Trigger: While `docker service create` (without `--detach`) is monitoring convergence progress, another process or user simultaneously updates the service to change its mode (e.g., `docker service update --mode global myservice`), causing the replicated mode or replica count to become nil on the next inspect.
Common situations: Concurrent service modifications during creation/convergence monitoring. Most likely in automation pipelines where one process creates the service and another immediately modifies it.
Related errors
- unrecognized service mode
- placement preference must be of the format
- 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
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/8ae9c47a31f3f03e.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/service/progress/progress.go:296
errMsg = errMsg[:maxWidth-1] + "…"
}
return errMsg
}
type replicatedProgressUpdater struct {
progressOut progress.Output
// used for mapping slots to a contiguous space
// this also causes progress bars to appear in order
slotMap map[int]int
initialized bool
done bool
}
func (u *replicatedProgressUpdater) update(service swarm.Service, tasks []swarm.Task, activeNodes map[string]struct{}, rollback bool) (bool, error) {
if service.Spec.Mode.Replicated == nil || service.Spec.Mode.Replicated.Replicas == nil {
return false, errors.New("no replica count")
}
replicas := *service.Spec.Mode.Replicated.Replicas
if !u.initialized {
u.slotMap = make(map[int]int)
// Draw progress bars in order
writeOverallProgress(u.progressOut, 0, int(replicas), rollback)
if replicas <= maxProgressBars {
for i := uint64(1); i <= replicas; i++ {
progress.Update(u.progressOut, fmt.Sprintf("%d/%d", i, replicas), " ")
}
}
u.initialized = true
}
tasksBySlot := u.tasksBySlot(tasks, activeNodes)View on GitHub (pinned to 4f84911bfe)