docker/cli · error
undefined volume
Error message
undefined volume %q
What it means
Returned by handleVolumeToMount when a service mounts a named volume whose source is not in the top-level volumes map and is not anonymous (volume.go:61-64). A non-anonymous volume mount must be declared at the top level (or be external) for the converter to build its Mount.
Solutions
- Declare the volume in the top-level `volumes:` block.
- If it already exists in Docker, mark it `external: true`.
- For an anonymous volume, omit the source (left of the colon).
Example fix
// before
services:
db:
image: postgres
volumes: [pgdata:/var/lib/postgresql/data]
// after
services:
db:
image: postgres
volumes: [pgdata:/var/lib/postgresql/data]
volumes:
pgdata: Defensive patterns
Strategy: validation
Validate before calling
func validateNamedVolumes(cfg *composetypes.Config) error {
for _, svc := range cfg.Services {
for _, v := range svc.Volumes {
if v.Type != "volume" && v.Type != "" { continue }
if v.Source == "" { continue } // anonymous
if _, ok := cfg.Volumes[v.Source]; !ok {
return fmt.Errorf("undefined volume %q", v.Source)
}
}
}
return nil
} Prevention
- Declare every named volume source in the top-level volumes block.
- Use external: true for pre-existing volumes.
- Omit the source for truly anonymous volumes.
When it happens
Trigger: A service volume entry of type volume (the default) with a non-empty `source` that has no entry in the stack volumes map. Reached at volume.go:62 when stackVolumes[volume.Source] is absent.
Common situations: Mounting `myvol:/data` but never declaring `volumes: myvol:`; renamed a volume inconsistently across files; forgot `external: true` for a pre-existing volume.
Related errors
- undefined network
- undefined secret
- undefined config
- images options are incompatible with type volume
- tmpfs options are incompatible with type volume
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/44e979a16b664513.
Report an issue: GitHub.
Appendix: source
Thrown at cli/compose/convert/volume.go:63
return mount.Mount{}, errors.New("images options are incompatible with type volume")
}
if volume.Tmpfs != nil {
return mount.Mount{}, errors.New("tmpfs options are incompatible with type volume")
}
if volume.Bind != nil {
return mount.Mount{}, errors.New("bind options are incompatible with type volume")
}
if volume.Cluster != nil {
return mount.Mount{}, errors.New("cluster options are incompatible with type volume")
}
// Anonymous volumes
if volume.Source == "" {
return result, nil
}
stackVolume, exists := stackVolumes[volume.Source]
if !exists {
return mount.Mount{}, fmt.Errorf("undefined volume %q", volume.Source)
}
result.Source = namespace.Scope(volume.Source)
result.VolumeOptions = &mount.VolumeOptions{}
if volume.Volume != nil {
result.VolumeOptions.NoCopy = volume.Volume.NoCopy
result.VolumeOptions.Subpath = volume.Volume.Subpath
}
if stackVolume.Name != "" {
result.Source = stackVolume.Name
}
// External named volumes
if stackVolume.External.External {
return result, nil
}View on GitHub (pinned to 4f84911bfe)