docker/cli · error
this node is not a swarm manager. Use "docker swarm init"…
Error message
this node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again
What it means
Thrown by checkDaemonIsSwarmManager (cli/command/stack/deploy.go:107) after an Info API call. Stack deploy must create swarm-scoped networks and services, which only a manager can do; if `res.Info.Swarm.ControlAvailable` is false (worker or non-swarm node), the operation is aborted before any resource is created.
Solutions
- Run the deploy from a manager node.
- Initialize a new swarm: `docker swarm init`.
- Join this node as a manager: `docker swarm join --token <manager-token> <manager-ip:2377>`.
- Verify with `docker info` that `Swarm: active` and `Is Manager: true`.
Example fix
// before (on a worker) docker stack deploy -c compose.yml mystack // after # on a manager node, or first: docker swarm init # or join as manager docker stack deploy -c compose.yml mystack
Defensive patterns
Strategy: validation
Validate before calling
// Verify manager status before stack operations.
res, err := apiClient.Info(ctx, client.InfoOptions{})
if err != nil { return err }
if !res.Info.Swarm.ControlAvailable {
return errors.New("target node is not a swarm manager; aborting deploy")
} Prevention
- Pin deploy commands to a known manager endpoint.
- In CI, assert `docker info --format '{{.Swarm.ControlAvailable}}'` is true first.
- Keep a list of manager node addresses and fail fast if unreachable.
When it happens
Trigger: Running `docker stack deploy` on a swarm worker node, or on a standalone engine that is not part of any swarm. The Info call succeeds but ControlAvailable is false.
Common situations: SSH'd into the wrong host (a worker); CI targets a worker by misconfiguration; the swarm was dissolved/rotated and this node lost manager status; load-balancer routed the Docker socket to a worker.
Related errors
- failed to update service
- failed to create service
- %s: %w
- cannot get label com.docker.stack.namespace for service
- specify a Compose file (with --compose-file)
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/8d725274c1d09dbb.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/stack/deploy.go:107
if opts.detach && !flags.Changed("detach") {
_, _ = fmt.Fprintln(dockerCLI.Err(), "Since --detach=false was not specified, tasks will be created in the background.\n"+
"In a future release, --detach=false will become the default.")
}
return deployCompose(ctx, dockerCLI, opts, cfg)
}
// checkDaemonIsSwarmManager does an Info API call to verify that the daemon is
// a swarm manager. This is necessary because we must create networks before we
// create services, but the API call for creating a network does not return a
// proper status code when it can't create a network in the "global" scope.
func checkDaemonIsSwarmManager(ctx context.Context, dockerCli command.Cli) error {
res, err := dockerCli.Client().Info(ctx, client.InfoOptions{})
if err != nil {
return err
}
if !res.Info.Swarm.ControlAvailable {
return errors.New(`this node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again`)
}
return nil
}
// pruneServices removes services that are no longer referenced in the source
func pruneServices(ctx context.Context, dockerCLI command.Cli, namespace convert.Namespace, services map[string]struct{}) {
apiClient := dockerCLI.Client()
oldServices, err := getStackServices(ctx, apiClient, namespace.Name())
if err != nil {
_, _ = fmt.Fprintln(dockerCLI.Err(), "Failed to list services:", err)
}
toRemove := make([]swarm.Service, 0, len(oldServices.Items))
for _, service := range oldServices.Items {
if _, exists := services[namespace.Descope(service.Spec.Name)]; !exists {
toRemove = append(toRemove, service)
}View on GitHub (pinned to 4f84911bfe)