docker/cli · error
links are only supported for user-defined networks
Error message
links are only supported for user-defined networks
What it means
Thrown by parseNetworkAttachmentOpt when links are supplied for a non-user-defined network. Legacy --link semantics (name aliasing) only work on user-defined networks in the modern code path; the default bridge uses legacy links differently and host/none/container: do not support them at all, so the CLI rejects the combination early.
Solutions
- Move the linked containers onto a user-defined network where DNS service discovery replaces --link entirely.
- If staying on host/none, remove the --link flags and use direct hostnames/IPs.
- On the default bridge, only legacy links are supported; switch to a user-defined bridge to use the modern link semantics.
Example fix
// before docker run --network host --link db:db alpine // after docker network create appnet docker run --network appnet --link db:db alpine
Defensive patterns
Strategy: validation
Validate before calling
func linksAllowed(networkMode string) bool {
return container.NetworkMode(networkMode).IsUserDefined()
}
for net, links := range desiredLinks {
if len(links) > 0 && !linksAllowed(net) {
return fmt.Errorf("links are only supported for user-defined networks: %s", net)
}
} Prevention
- Migrate --link usage to user-defined network DNS service discovery.
- When changing network_mode, audit and remove --link flags that no longer apply.
- Prefer --network-alias on a user-defined bridge over legacy links.
When it happens
Trigger: `docker run --network host --link foo:bar alpine` or `--network none --link foo`. Also via advanced notation `--network host:link=foo:bar`. The IsUserDefined() check at opts.go:863 returns false and ep.Links is non-empty.
Common situations: Migrating from default-bridge --link usage to host networking while keeping the --link flag. Misconfigured compose that pairs links with external/host networks. Stale legacy scripts after switching network modes.
Related errors
- network-scoped aliases are only supported for user-defined…
- conflicting options: cannot specify both --link and…
- conflicting options: cannot specify both --link-local-ip…
- no name set for network
- timeout waiting for stats
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/51490a738334547e.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/container/opts.go:868
if copts.macAddress != "" {
n.MacAddress = copts.macAddress
}
if copts.linkLocalIPs.Len() > 0 {
n.LinkLocalIPs = toNetipAddrSlice(copts.linkLocalIPs.GetSlice())
}
return nil
}
func parseNetworkAttachmentOpt(ep opts.NetworkAttachmentOpts) (*network.EndpointSettings, error) {
if strings.TrimSpace(ep.Target) == "" {
return nil, errors.New("no name set for network")
}
if !container.NetworkMode(ep.Target).IsUserDefined() {
if len(ep.Aliases) > 0 {
return nil, errors.New("network-scoped aliases are only supported for user-defined networks")
}
if len(ep.Links) > 0 {
return nil, errors.New("links are only supported for user-defined networks")
}
}
epConfig := &network.EndpointSettings{
GwPriority: ep.GwPriority,
}
epConfig.Aliases = append(epConfig.Aliases, ep.Aliases...)
if len(ep.DriverOpts) > 0 {
epConfig.DriverOpts = make(map[string]string)
epConfig.DriverOpts = ep.DriverOpts
}
if len(ep.Links) > 0 {
epConfig.Links = ep.Links
}
if ep.IPv4Address.IsValid() || ep.IPv6Address.IsValid() || len(ep.LinkLocalIPs) > 0 {
epConfig.IPAMConfig = &network.EndpointIPAMConfig{
IPv4Address: ep.IPv4Address,
IPv6Address: ep.IPv6Address,View on GitHub (pinned to 4f84911bfe)