{"record":{"id":"ceeb139e9e79af84","repo":"docker/cli","slug":"volume-s-volume-external-name-and-volume-name-co","errorCode":null,"errorMessage":"volume %s: volume.external.name and volume.name conflict; only use volume.name","messagePattern":"volume (.+?): volume\\.external\\.name and volume\\.name conflict; only use volume\\.name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/compose/loader/loader.go","lineNumber":595,"sourceCode":"\tvolumes := make(map[string]types.VolumeConfig)\n\tif err := Transform(source, &volumes); err != nil {\n\t\treturn volumes, err\n\t}\n\n\tfor name, volume := range volumes {\n\t\tif !volume.External.External {\n\t\t\tcontinue\n\t\t}\n\t\tswitch {\n\t\tcase volume.Driver != \"\":\n\t\t\treturn nil, externalVolumeError(name, \"driver\")\n\t\tcase len(volume.DriverOpts) > 0:\n\t\t\treturn nil, externalVolumeError(name, \"driver_opts\")\n\t\tcase len(volume.Labels) > 0:\n\t\t\treturn nil, externalVolumeError(name, \"labels\")\n\t\tcase volume.External.Name != \"\":\n\t\t\tif volume.Name != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"volume %s: volume.external.name and volume.name conflict; only use volume.name\", name)\n\t\t\t}\n\t\t\tif versions.GreaterThanOrEqualTo(version, \"3.4\") {\n\t\t\t\tlogrus.Warnf(\"volume %s: volume.external.name is deprecated in favor of volume.name\", name)\n\t\t\t}\n\t\t\tvolume.Name = volume.External.Name\n\t\t\tvolume.External.Name = \"\"\n\t\tcase volume.Name == \"\":\n\t\t\tvolume.Name = name\n\t\t}\n\t\tvolume.Extras = loadExtras(name, source)\n\t\tvolumes[name] = volume\n\t}\n\treturn volumes, nil\n}\n\n// LoadSecrets produces a SecretConfig map from a compose file Dict\n// the source Dict is not validated if directly used. Use Load() to enable validation\nfunc LoadSecrets(source map[string]any, details types.ConfigDetails) (map[string]types.SecretConfig, error) {","sourceCodeStart":577,"sourceCodeEnd":613,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/compose/loader/loader.go#L577-L613","documentation":"Thrown by LoadVolumes for an external volume that sets BOTH `external.name` (deprecated) and the top-level `name`. Like the network case, the two rename the external resource and are mutually exclusive.","triggerScenarios":"A volume entry has `external: true` (or `external: {name: x}`) and both `external.name` and `name` are non-empty.","commonSituations":"Migrating off the deprecated `external.name` field; merge of two override files each setting a different field.","solutions":["Keep `name` and remove `external.name`.","Or keep only the deprecated `external.name` and remove `name` (not recommended)."],"exampleFix":"# before\nvolumes:\n  data:\n    external:\n      name: prod-data\n    name: prod-data\n# after\nvolumes:\n  data:\n    external: true\n    name: prod-data","handlingStrategy":"validation","validationCode":"func validateVolumeName(name string, vol map[string]any) error {\n    ext, _ := vol[\"external\"]\n    var extName string\n    if em, ok := ext.(map[string]any); ok {\n        extName, _ = em[\"name\"].(string)\n    }\n    topName, _ := vol[\"name\"].(string)\n    if ext == true && extName != \"\" && topName != \"\" {\n        return fmt.Errorf(\"volume %s: set only one of external.name or name\", name)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Migrate fully off `external.name` to `name`.","Avoid setting both fields across merged override files.","Lint with `docker compose config`."],"tags":["compose","volume","external","conflict","deprecation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}