docker/compose · error

destination " : " must be a directory

Error message

destination "%s:%s" must be a directory

What it means

Error "destination "%s:%s" must be a directory" thrown in docker/compose.

Solutions

  1. Point the destination at an existing directory inside the container, ending the path with a slash if needed.
  2. Create the directory in the container first with docker compose exec <service> mkdir -p <path>.

When it happens

Trigger: When copying multiple source files into a container with 'docker compose cp', the in-container destination must be an existing directory and it is not.

Common situations: Multiple sources (or a wildcard-expanded copy) were given with a destination path that is a file or does not exist inside the container.


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/439268308eaf9bdc. Report an issue: GitHub.

Appendix: source

Thrown at pkg/compose/cp.go:207

	// path exists, in which case the copy may still succeed. If there is any
	// type of conflict (e.g., non-directory overwriting an existing directory
	// or vice versa) the extraction will fail. If the destination simply did
	// not exist, but the parent directory does, the extraction will still
	// succeed.
	if err == nil {
		dstInfo.Exists, dstInfo.IsDir = true, dstStat.Mode.IsDir()
	}

	var (
		content         io.Reader
		resolvedDstPath string
	)

	if srcPath == "-" {
		content = s.stdin()
		resolvedDstPath = dstInfo.Path
		if !dstInfo.IsDir {
			return fmt.Errorf("destination \"%s:%s\" must be a directory", containerID, dstPath)
		}
	} else {
		// Prepare source copy info.
		srcInfo, err := archive.CopyInfoSourcePath(srcPath, opts.FollowLink)
		if err != nil {
			return err
		}

		srcArchive, err := archive.TarResource(srcInfo)
		if err != nil {
			return err
		}
		defer srcArchive.Close() //nolint:errcheck

		// With the stat info about the local source as well as the
		// destination, we have enough information to know whether we need to
		// alter the archive that we upload so that when the server extracts
		// it to the specified directory in the container we get the desired

View on GitHub (pinned to ddc4b044b6)