docker/cli · error

cannot merge services

Error message

cannot merge services: %w

What it means

Thrown by merge() when merging the Services slices of two compose Configs fails. It wraps the error from mergeServices, which itself wraps per-service merge errors (e.g. `cannot merge service X: ...`). The underlying cause is typically mergo.Merge failing on incompatible struct values or a transformer error.

Solutions

  1. Inspect the wrapped `%w` cause: it names the specific service and the underlying mergo error.
  2. Make the conflicting service fields consistent across files (same type/shape).
  3. Simplify the override to only change scalar values, not structural fields.

Example fix

# before
# base: web.ulimits.nproc: 65535
# override: web.ulimits.nproc: { soft: 1024 }  # shape mismatch
# after
# base: web.ulimits.nproc: { soft: 65535, hard: 65535 }
# override: web.ulimits.nproc: { soft: 1024, hard: 1024 }
Defensive patterns

Strategy: try-catch

Validate before calling

// Before merging, ensure services with the same name share field shapes.
func validateMergeableServices(base, override []types.ServiceConfig) error {
    idx := map[string]types.ServiceConfig{}
    for _, s := range base {
        idx[s.Name] = s
    }
    for _, o := range override {
        b, ok := idx[o.Name]
        if !ok {
            continue
        }
        // example shape check: ulimits must both be map or both empty
        if err := compatibleUlimits(b.Ulimits, o.Ulimits); err != nil {
            return fmt.Errorf("service %s: %w", o.Name, err)
        }
    }
    return nil
}

Try / catch

// merge() returns errors; wrap to add file context.
func loadMultiple(details types.ConfigDetails) (*types.Config, error) {
    cfg, err := Load(details)
    if err != nil {
        // errors.Is/As to detect "cannot merge services"
        var mergeErr *mergeErrMatcher
        if errors.As(err, &mergeErr) {
            return nil, fmt.Errorf("override merge failed (align service shapes across -f files): %w", err)
        }
        return nil, err
    }
    return cfg, nil
}

Prevention

When it happens

Trigger: Loading multiple compose files (base + override) where a service with the same name has structurally incompatible fields that mergo's transformers cannot reconcile (e.g. conflicting ulimits, nil-pointer fields).

Common situations: Using `-f base.yml -f override.yml` (or COMPOSE_FILE) with services that disagree on types; overriding a service that was defined differently in base.

Related errors


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

Appendix: source

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

)

type specials struct {
	m map[reflect.Type]func(dst, src reflect.Value) error
}

func (s *specials) Transformer(t reflect.Type) func(dst, src reflect.Value) error {
	if fn, ok := s.m[t]; ok {
		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)
		}

View on GitHub (pinned to 4f84911bfe)