docker/cli · error

cannot merge networks

Error message

cannot merge networks: %w

What it means

Thrown by merge() when mergo.Map fails merging the `Networks` maps of two compose Configs. Analogous to the volumes case: merges map[string]NetworkConfig by key and surfaces a mergo error on incompatible values.

Solutions

  1. Inspect the wrapped `%w` cause for the offending network key.
  2. Align the network definition across all `-f` files (external vs managed, same driver).
  3. Override only scalar fields (name, driver) rather than flipping external on/off across files.

Example fix

# before
# base.yml
networks:
  appnet:
    driver: bridge
# override.yml
networks:
  appnet:
    external: true
# after
networks:
  appnet:
    driver: bridge
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure networks with the same key are structurally compatible before merge.
func validateMergeableNetworks(base, override map[string]types.NetworkConfig) error {
    for k, ov := range override {
        bv, ok := base[k]
        if !ok {
            continue
        }
        if bv.External.External != ov.External.External {
            return fmt.Errorf("network %s: external flag differs across files", k)
        }
    }
    return nil
}

Try / catch

// Surface the wrapped mergo cause clearly.
if err := cfg.Load(details); err != nil {
    var me interface{ Unwrap() error }
    if errors.As(err, &me) {
        return fmt.Errorf("network merge failed: %w", me.Unwrap())
    }
    return err
}

Prevention

When it happens

Trigger: Merging two compose files where the Networks map merge raises a mergo error — typically when override and base define the same network name with structurally incompatible config.

Common situations: One file makes a network external, another defines it with driver/labels; mixing attachable/enable_ipv6 differently across overrides.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/45d5975f38a12ae1. Report an issue: GitHub.

Appendix: source

Thrown at cli/compose/loader/merge.go:42

		return fn
	}
	return nil
}

func merge(configs []*types.Config) (*types.Config, error) {
	base := configs[0]
	for _, override := range configs[1:] {
		var errs []error
		if services, err := mergeServices(base.Services, override.Services); err != nil {
			errs = append(errs, fmt.Errorf("cannot merge services: %w", err))
		} else {
			base.Services = services
		}
		if err := mergo.Map(&base.Volumes, &override.Volumes, mergo.WithOverride); err != nil {
			errs = append(errs, fmt.Errorf("cannot merge volumes: %w", err))
		}
		if err := mergo.Map(&base.Networks, &override.Networks, mergo.WithOverride); err != nil {
			errs = append(errs, fmt.Errorf("cannot merge networks: %w", err))
		}
		if err := mergo.Map(&base.Secrets, &override.Secrets, mergo.WithOverride); err != nil {
			errs = append(errs, fmt.Errorf("cannot merge secrets: %w", err))
		}
		if err := mergo.Map(&base.Configs, &override.Configs, mergo.WithOverride); err != nil {
			errs = append(errs, fmt.Errorf("cannot merge configs: %w", err))
		}
		if err := errors.Join(errs...); err != nil {
			return nil, errors.Join(fmt.Errorf("failed to merge file %s", override.Filename), err)
		}
	}
	return base, nil
}

func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig, error) {
	mergeOpts := []func(*mergo.Config){
		mergo.WithAppendSlice,
		mergo.WithOverride,

View on GitHub (pinned to 4f84911bfe)