docker/cli · error
must specify at least one container source
Error message
must specify at least one container source
What it means
runCopy switches on the computed direction. If neither source nor destination contains a container specifier (direction == 0, the default case at line 244-245), it returns errors.New("must specify at least one container source"). At least one side of a `docker cp` must be a CONTAINER:PATH; a pure local-to-local copy is not what `docker cp` does (use cp/rsync instead).
Solutions
- Prefix one side with the container: `docker cp ./file.txt web:/tmp` or `docker cp web:/tmp/file ./`.
- If you genuinely want a local copy, use `cp`/`rsync`, not `docker cp`.
- Re-check the argument order: source and destination, with at least one as CONTAINER:PATH.
Example fix
# before (no container involved) docker cp ./file.txt ./backup/ # after docker cp ./file.txt web:/tmp/
Defensive patterns
Strategy: validation
Validate before calling
// Ensure at least one side is a container spec:
srcCtr, _ := splitCpArg(src)
dstCtr, _ := splitCpArg(dst)
if srcCtr == "" && dstCtr == "" {
return errors.New("must specify at least one container (CONTAINER:PATH) as source or destination")
} Type guard
func involvesContainer(args ...string) bool {
for _, a := range args { if ctr, _ := splitCpArg(a); ctr != "" { return true } }
return false
} Try / catch
if err := runCopy(ctx, cli, opts); err != nil {
if strings.Contains(err.Error(), "must specify at least one container source") {
// guide user to add CONTAINER:PATH on one side
}
return err
} Prevention
- Prefix one argument with CONTAINER: in every `docker cp`.
- Use plain cp/rsync for local-to-local copies.
- Validate argv shape in wrappers.
When it happens
Trigger: Running `docker cp ./file.txt ./backup/` — both arguments lack the CONTAINER:PATH form, so splitCpArg returns "" for both containers and direction stays 0. Also `docker cp a.txt b.txt`.
Common situations: Users treating `docker cp` like the regular cp; forgetting the CONTAINER: prefix; copy-paste of two local paths; typos dropping the container name.
Related errors
- source can not be empty
- destination can not be empty
- copying between containers is not supported
- container ID file found, make sure the other container…
- got a device
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/1d70827a5ac5492b.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/container/cp.go:245
var direction copyDirection
if srcContainer != "" {
direction |= fromContainer
copyConfig.container = srcContainer
}
if destContainer != "" {
direction |= toContainer
copyConfig.container = destContainer
}
switch direction {
case fromContainer:
return copyFromContainer(ctx, dockerCli, copyConfig)
case toContainer:
return copyToContainer(ctx, dockerCli, copyConfig)
case acrossContainers:
return errors.New("copying between containers is not supported")
default:
return errors.New("must specify at least one container source")
}
}
func resolveLocalPath(localPath string) (absPath string, _ error) {
absPath, err := filepath.Abs(localPath)
if err != nil {
return "", err
}
return archive.PreserveTrailingDotOrSeparator(absPath, localPath), nil
}
func copyFromContainer(ctx context.Context, dockerCLI command.Cli, copyConfig cpConfig) (err error) {
dstPath := copyConfig.destPath
srcPath := copyConfig.sourcePath
if dstPath != "-" {
// Get an absolute destination path.
dstPath, err = resolveLocalPath(dstPath)View on GitHub (pinned to 4f84911bfe)