{"record":{"id":"ba1c756414ee414f","repo":"docker/compose","slug":"destination-can-not-be-empty","errorCode":null,"errorMessage":"destination can not be empty","messagePattern":"destination can not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/compose/cp.go","lineNumber":56,"sourceCode":"\tfollowLink  bool\n\tcopyUIDGID  bool\n}\n\nfunc copyCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *BackendOptions) *cobra.Command {\n\topts := copyOptions{\n\t\tProjectOptions: p,\n\t}\n\tcopyCmd := &cobra.Command{\n\t\tUse: `cp [OPTIONS] SERVICE:SRC_PATH DEST_PATH|-\n\tdocker compose cp [OPTIONS] SRC_PATH|- SERVICE:DEST_PATH`,\n\t\tShort: \"Copy files/folders between a service container and the local filesystem\",\n\t\tArgs:  cli.ExactArgs(2),\n\t\tPreRunE: Adapt(func(ctx context.Context, args []string) error {\n\t\t\tif args[0] == \"\" {\n\t\t\t\treturn errors.New(\"source can not be empty\")\n\t\t\t}\n\t\t\tif args[1] == \"\" {\n\t\t\t\treturn errors.New(\"destination can not be empty\")\n\t\t\t}\n\t\t\treturn nil\n\t\t}),\n\t\tRunE: AdaptCmd(func(ctx context.Context, cmd *cobra.Command, args []string) error {\n\t\t\topts.source = args[0]\n\t\t\topts.destination = args[1]\n\t\t\treturn runCopy(ctx, dockerCli, backendOptions, opts)\n\t\t}),\n\t\tValidArgsFunction: completeServiceNames(dockerCli, p),\n\t}\n\n\tflags := copyCmd.Flags()\n\tflags.IntVar(&opts.index, \"index\", 0, \"Index of the container if service has multiple replicas\")\n\tflags.BoolVar(&opts.all, \"all\", false, \"Include containers created by the run command\")\n\tflags.BoolVarP(&opts.followLink, \"follow-link\", \"L\", false, \"Always follow symbol link in SRC_PATH\")\n\tflags.BoolVarP(&opts.copyUIDGID, \"archive\", \"a\", false, \"Archive mode (copy all uid/gid information)\")\n\n\treturn copyCmd","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/cmd/compose/cp.go#L38-L74","documentation":"The counterpart of the source check: docker compose cp validates in PreRunE that args[1] — the destination, either DEST_PATH, '-', or SERVICE:DEST_PATH — is not the empty string. With cli.ExactArgs(2) already guaranteeing two positional args, this catches a present-but-empty second argument (quoted empty string) before runCopy executes.","triggerScenarios":"Running `docker compose cp web:/app/log.txt \"\"`, or scripts where the destination variable is unset/empty but quoted so the shell still passes an empty argument, e.g. `docker compose cp src \"$DEST\"` with DEST unset.","commonSituations":"CI variables not exported into the job environment; typos in variable names (e.g. $DESTNATION); build scripts assuming a default output path that was never set.","solutions":["Set the destination explicitly to a concrete path or '-', verifying the variable first: `: \"${DEST:?destination required}\"`.","When piping to stdout, pass '-' as the destination instead of an empty string.","Audit the surrounding script for misspelled or unexported variables feeding the cp command."],"exampleFix":"# before\ndocker compose cp web:/app/log.txt \"$DEST\"\n# DEST unset -> empty-string arg\n\n# after\n: \"${DEST:?destination required}\"\ndocker compose cp web:/app/log.txt \"$DEST\"","handlingStrategy":"validation","validationCode":": \"${DEST:?docker compose cp needs a non-empty destination}\"\ndocker compose cp \"$SRC\" \"$DEST\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default destinations explicitly in scripts: DEST=\"${DEST:-./out.bin}\".","Export CI variables or they expand empty when quoted."],"tags":["cli","cp","validation","arguments"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}