docker/cli · error
network is declared as external, but could not be found…
Error message
network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed
What it means
Raised by validateExternalNetworks when a Compose network declared as external (external: true) does not exist on the Swarm. External networks must be pre-created by the operator because stack deploy will not create them; the check fails fast with a NotFound (errdefs.IsNotFound) from NetworkInspect.
Solutions
- Pre-create the network as swarm-scoped overlay: `docker network create -d overlay <name>`.
- Make the compose entry match the real network name (external networks use their actual name, no stack prefix).
- If the network should be managed by the stack, remove `external: true` so stack deploy creates it.
- Document required pre-existing networks in your deploy runbook/automation.
Example fix
# before (compose.yml)
networks:
shared:
external: true
# after
docker network create -d overlay shared
docker stack deploy -c compose.yml mystack Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: ensure each external network exists and is swarm-scoped before deploy
func ensureExternalNetworks(ctx context.Context, c client.NetworkAPIClient, names []string) error {
for _, name := range names {
res, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
if errdefs.IsNotFound(err) {
return fmt.Errorf("external network %q missing; create it with: docker network create -d overlay %s", name, name)
} else if err != nil {
return err
} else if res.Network.Scope != "swarm" {
return fmt.Errorf("external network %q is %q-scoped, needs swarm", name, res.Network.Scope)
}
}
return nil
} Try / catch
if err := stackDeploy(ctx, cli, opts, cfg); err != nil {
if strings.Contains(err.Error(), "declared as external, but could not be found") {
// prompt operator to pre-create, then retry
}
return err
} Prevention
- Run a pre-flight check that inspects every external network before deploy.
- Provision shared networks as part of infra bootstrap, not the stack.
- Keep external network names in a single documented inventory.
When it happens
Trigger: Deploying a stack whose compose file declares `networks: { foo: { external: true } }` while no network named 'foo' exists. The loop in deploy_composefile.go:90 calls NetworkInspect for each external network and, on NotFound, returns this error before any service is deployed.
Common situations: Forgetting to `docker network create -d overlay foo` before deploying; using a different name in compose than the actual network; deploying against a fresh Swarm that hasn't had shared networks provisioned; environment drift between staging and prod Swarms.
Related errors
- network is declared as external, but it is not in the right…
- failed to create network
- nothing found in stack
- this node is not a swarm manager. Use "docker swarm init"…
- cannot get label com.docker.stack.namespace for service
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/6c0fa91aadd1571f.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/stack/deploy_composefile.go:100
}
for nw := range serviceConfig.Networks {
serviceNetworks[nw] = struct{}{}
}
}
return serviceNetworks
}
func validateExternalNetworks(ctx context.Context, apiClient client.NetworkAPIClient, externalNetworks []string) error {
for _, networkName := range externalNetworks {
if !container.NetworkMode(networkName).IsUserDefined() {
// Networks that are not user defined always exist on all nodes as
// local-scoped networks, so there's no need to inspect them.
continue
}
res, err := apiClient.NetworkInspect(ctx, networkName, client.NetworkInspectOptions{})
switch {
case errdefs.IsNotFound(err):
return fmt.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
case err != nil:
return err
case res.Network.Scope != "swarm":
return fmt.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"", networkName, res.Network.Scope)
}
}
return nil
}
func createSecrets(ctx context.Context, dockerCLI command.Cli, secrets []swarm.SecretSpec) error {
apiClient := dockerCLI.Client()
for _, secretSpec := range secrets {
res, err := apiClient.SecretInspect(ctx, secretSpec.Name, client.SecretInspectOptions{})
switch {
case err == nil:
// secret already exists, then we update that
_, err := apiClient.SecretUpdate(ctx, res.Secret.ID, client.SecretUpdateOptions{View on GitHub (pinned to 4f84911bfe)