{"record":{"id":"06f2e44ee1342a56","repo":"docker/compose","slug":"unknown-copy-direction","errorCode":null,"errorMessage":"unknown copy direction","messagePattern":"unknown copy direction","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/compose/cp.go","lineNumber":74,"sourceCode":"\tvar direction copyDirection\n\tvar serviceName string\n\tvar copyFunc func(ctx context.Context, containerID string, srcPath string, dstPath string, opts api.CopyOptions) error\n\tif srcService != \"\" {\n\t\tdirection |= fromService\n\t\tserviceName = srcService\n\t\tcopyFunc = s.copyFromContainer\n\t}\n\tif destService != \"\" {\n\t\tdirection |= toService\n\t\tserviceName = destService\n\t\tcopyFunc = s.copyToContainer\n\t}\n\tif direction == acrossServices {\n\t\treturn errors.New(\"copying between services is not supported\")\n\t}\n\n\tif direction == 0 {\n\t\treturn errors.New(\"unknown copy direction\")\n\t}\n\n\tcontainers, err := s.listContainersTargetedForCopy(ctx, projectName, options, direction, serviceName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tg := errgroup.Group{}\n\tfor _, cont := range containers {\n\t\tctr := cont\n\t\tg.Go(func() error {\n\t\t\tname := getCanonicalContainerName(ctr)\n\t\t\tvar msg string\n\t\t\tif direction == fromService {\n\t\t\t\tmsg = fmt.Sprintf(\"%s:%s to %s\", name, srcPath, dstPath)\n\t\t\t} else {\n\t\t\t\tmsg = fmt.Sprintf(\"%s to %s:%s\", srcPath, name, dstPath)\n\t\t\t}","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/compose/cp.go#L56-L92","documentation":"The copy direction is derived from service prefixes: a prefix on Source sets fromService, a prefix on Destination sets toService. If neither argument has a SERVICE: prefix, direction stays 0 and Compose cannot identify any container to talk to, so it fails fast with 'unknown copy direction'. Host-to-host copying is not something compose cp does.","triggerScenarios":"Running `docker compose cp ./file.txt ./other.txt` or api.Copy with options.Source and options.Destination that both lack the `service:` prefix after splitCpArg.","commonSituations":"Typos where the colon is dropped (`docker compose cp data.json web:/app` vs `web /app`), shell variable expansion producing an empty service name (`$svc:/path` with svc unset), or misunderstanding compose cp as a generic file-copy tool between host paths.","solutions":["Prefix exactly one side with the service name: `docker compose cp ./file.txt web:/app/file.txt`","If you genuinely want host-to-host copies, use plain `cp`/`rsync` — compose cp always involves containers","Check shell variables used in the command (e.g. `echo \"$svc:/path\"`) to ensure the service name is not empty","Verify the service exists with `docker compose ps` so the prefix matches a running service"],"exampleFix":"# before\ndocker compose cp ./app.conf \"${SVC:-}:/etc/app.conf\"\n# after\nSVC=web docker compose cp ./app.conf \"${SVC}:/etc/app.conf\"","handlingStrategy":"validation","validationCode":"# ensure at least one side carries a service prefix and the variable is set\n: \"${SVC:?SVC must be set}\"\n[ -n \"${SVC}\" ] && docker compose cp ./file \"${SVC}:/path\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["set -u / :? guards on variables used to build SERVICE:PATH strings","Always test compose cp invocations with fully expanded arguments first (echo them)"],"tags":["copy","cli","validation","compose-cp"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}