docker/cli · error

destination " : " must be a directory or a regular file

Error message

destination "%s:%s" must be a directory or a regular file: %w

What it means

Returned during `docker cp` when the destination path inside the container exists and stat-succeeds but its file mode fails command.ValidateOutputPathFileMode (cli/command/container/cp.go:386-388). That validator only accepts directories or regular files; any other mode bit (device, socket, named pipe/FIFO, or a non-regular/symlink-targeted irregular file) is rejected. The destination container and path are included in the message.

Solutions

  1. Choose a destination path that is a regular file or an existing directory.
  2. If targeting a directory, ensure it actually is a directory (stat it inside the container: docker exec <c> test -d <path>).
  3. Avoid copying onto sockets/devices; copy to a normal path and let the application read it.
  4. Verify the destination is not a symlink to an irregular file.

Example fix

# before
docker cp ./file.txt mycontainer:/var/run/docker.sock   # socket is not dir/regular
# after
docker cp ./file.txt mycontainer:/tmp/file.txt
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the container destination is a dir or regular file before copying.
func validateCpDestination(ctx context.Context, c client.APIClient, container, path string) error {
    st, err := c.ContainerStatPath(ctx, container, client.ContainerStatPathOptions{Path: path})
    if err != nil { return nil } // absent destination is allowed by cp
    mode := st.Stat.Mode
    if !mode.IsDir() && mode&os.ModeType == 0 { return nil } // regular file
    return fmt.Errorf("destination mode (%v) is not a directory or regular file", mode)
}

Type guard

// isDirOrRegular reports whether an os.FileMode is a dir or regular file.
func isDirOrRegular(m os.FileMode) bool { return m.IsDir() || m&os.ModeType == 0 }

Prevention

When it happens

Trigger: Copying to a container path that resolves to a device node (/dev/*), a unix socket, a named pipe, or any non-regular non-directory file. The check runs after following symlinks on the destination, so a symlink whose target is irregular also triggers it.

Common situations: Destination path is /dev/something or /var/run/docker.sock (a socket); copying into a FIFO used by a service; or a path that became a device via a bind-mount inside the container.

Related errors


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

Appendix: source

Thrown at cli/command/container/cp.go:387

	// Prepare destination copy info by stat-ing the container path.
	dstInfo := archive.CopyInfo{Path: dstPath}
	if dst, err := apiClient.ContainerStatPath(ctx, copyConfig.container, client.ContainerStatPathOptions{Path: dstPath}); err == nil {
		// If the destination is a symbolic link, we should evaluate it.
		if dst.Stat.Mode&os.ModeSymlink != 0 {
			linkTarget := dst.Stat.LinkTarget
			if !isAbs(linkTarget) {
				// Join with the parent directory.
				dstParent, _ := archive.SplitPathDirEntry(dstPath)
				linkTarget = filepath.Join(dstParent, linkTarget)
			}

			dstInfo.Path = linkTarget
			dst, err = apiClient.ContainerStatPath(ctx, copyConfig.container, client.ContainerStatPathOptions{Path: linkTarget})
		}
		// Validate the destination path
		if err == nil {
			if err := command.ValidateOutputPathFileMode(dst.Stat.Mode); err != nil {
				return fmt.Errorf(`destination "%s:%s" must be a directory or a regular file: %w`, copyConfig.container, dstPath, err)
			}
			dstInfo.Exists, dstInfo.IsDir = true, dst.Stat.Mode.IsDir()
		}

		// Ignore any error and assume that the parent directory of the destination
		// 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.
		_ = err // Intentionally ignore stat errors (see above)
	}

	var (
		content         io.ReadCloser
		resolvedDstPath string
		copiedSize      int64
		contentSize     int64

View on GitHub (pinned to 4f84911bfe)