docker/cli · error

%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict…

Error message

%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict; only use %[1]s.name

What it means

Returned by loadFileObjectConfig for secrets and configs when `external: true` is set and both `external.name` (deprecated) and `name` are present. objType is interpolated as 'secret' or 'config'.

Solutions

  1. Remove the deprecated `external.name` and keep `name`.
  2. Ensure only one of the two fields is set across all merged compose files.

Example fix

# before
secrets:
  token:
    external:
      name: prod-token
    name: prod-token
# after
secrets:
  token:
    external: true
    name: prod-token
Defensive patterns

Strategy: validation

Validate before calling

func validateFileObjectName(objType, name string, obj map[string]any) error {
    ext, _ := obj["external"]
    var extName string
    if em, ok := ext.(map[string]any); ok {
        extName, _ = em["name"].(string)
    }
    topName, _ := obj["name"].(string)
    if ext == true && extName != "" && topName != "" {
        return fmt.Errorf("%s %s: set only one of external.name or name", objType, name)
    }
    return nil
}

Prevention

When it happens

Trigger: A `secrets:` or `configs:` entry has `external: true` plus `external.name` and `name` both non-empty.

Common situations: Porting an old compose file using `external.name` to the modern `name` field and leaving both; CI override file sets `name` while base sets `external.name`.

Related errors


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

Appendix: source

Thrown at cli/compose/loader/loader.go:656

		obj, err := loadFileObjectConfig(name, "config", types.FileObjectConfig(config), details)
		if err != nil {
			return nil, err
		}
		configConfig := types.ConfigObjConfig(obj)
		configConfig.Extras = loadExtras(name, source)
		configs[name] = configConfig
	}
	return configs, nil
}

func loadFileObjectConfig(name string, objType string, obj types.FileObjectConfig, details types.ConfigDetails) (types.FileObjectConfig, error) {
	// if "external: true"
	switch {
	case obj.External.External:
		// handle deprecated external.name
		if obj.External.Name != "" {
			if obj.Name != "" {
				return obj, fmt.Errorf("%[1]s %[2]s: %[1]s.external.name and %[1]s.name conflict; only use %[1]s.name", objType, name)
			}
			if versions.GreaterThanOrEqualTo(details.Version, "3.5") {
				logrus.Warnf("%[1]s %[2]s: %[1]s.external.name is deprecated in favor of %[1]s.name", objType, name)
			}
			obj.Name = obj.External.Name
			obj.External.Name = ""
		} else if obj.Name == "" {
			obj.Name = name
		}
		// if not "external: true"
	case obj.Driver != "":
		if obj.File != "" {
			return obj, fmt.Errorf("%[1]s %[2]s: %[1]s.driver and %[1]s.file conflict; only use %[1]s.driver", objType, name)
		}
	default:
		obj.File = absPath(details.WorkingDir, obj.File)
	}

View on GitHub (pinned to 4f84911bfe)