nektos/act · 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 the container options string declares links (--network name:alias or --link style link entries parsed into ep.Links) against a network mode that is not user-defined. Docker links are a legacy feature that only function on networks you created yourself; they are meaningless on 'host', 'none', the predefined 'bridge', or 'default'. The parser therefore rejects the combination before ever contacting the daemon.

Source

Thrown at pkg/container/docker_cli.go:875

	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 4f41128141)

Solutions

  1. Drop the --link flag; on user-defined networks (including act's default per-run network) services are reachable by service name via DNS.
  2. If you genuinely need legacy links, create a user-defined network first ('docker network create act-net') and use '--network act-net' plus the link.
  3. Replace link-based hostnames with the service name already registered by act's service containers.
  4. Audit the options string for stale compose-v1 syntax when migrating a workflow.

Example fix

# before
container:
  image: node:20
  options: --network host --link myredis:redis

# after
container:
  image: node:20
  options: --network host
services:
  redis:
    image: redis:7
Defensive patterns

Strategy: validation

Validate before calling

package main

import (
	"fmt"
	"strings"
)

func validateNoLinksOnBuiltinNetwork(options string) error {
	fields := strings.Fields(options)
	builtin := false
	for _, f := range fields {
		v := strings.TrimPrefix(strings.TrimPrefix(f, "--network"), "=")
		if strings.HasPrefix(f, "--network") && !strings.ContainsAny(v, ":.") {
			switch v {
			case "host", "bridge", "none", "default":
				builtin = true
			}
		}
		if f == "--link" || strings.HasPrefix(f, "--link=") {
			if builtin {
				return fmt.Errorf("--link cannot be combined with a built-in network")
			}
		}
	}
	return nil
}

Try / catch

err := runPlan(plan)
if err != nil && strings.Contains(err.Error(), "links are only supported for user-defined networks") {
    // drop legacy --link flags and rely on service-name DNS, then retry
    cfg.ContainerOptions = stripFlag(cfg.ContainerOptions, "--link")
    err = runPlan(plan)
}

Prevention

When it happens

Trigger: A workflow container options string like 'options: --network bridge --link redis:redis' where parsing yields a Links list on a non-user-defined target, or '--network host:alias(link)'. Any NetworkAttachmentOpts whose Target fails IsUserDefined() while ep.Links is non-empty.

Common situations: Porting legacy docker-compose v1 style 'links:' blocks into act container options; combining '--network host' (often set for performance or to reach host services) with a copied '--link' flag; misunderstanding that links are deprecated in favor of user-defined network DNS.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/721c94e8066f8730. Report an issue: GitHub.