golang/go · error
destination is not a directory
Error message
destination is not a directory
What it means
Returned by the script Cp command when more than two arguments are supplied (multiple sources to one destination) but the destination path does not resolve to an existing directory. Cp requires that a multi-source invocation copy into a directory; otherwise the copy is ambiguous. The error is wrapped as an fs.PathError with Op "cp" and the destination Path so it carries the offending path.
Source
Thrown at src/cmd/internal/script/cmds.go:292
func Cp() Cmd {
return Command(
CmdUsage{
Summary: "copy files to a target file or directory",
Args: "src... dst",
Detail: []string{
"src can include 'stdout' or 'stderr' to copy from the script's stdout or stderr buffer.",
},
},
func(s *State, args ...string) (WaitFunc, error) {
if len(args) < 2 {
return nil, ErrUsage
}
dst := s.Path(args[len(args)-1])
info, err := os.Stat(dst)
dstDir := err == nil && info.IsDir()
if len(args) > 2 && !dstDir {
return nil, &fs.PathError{Op: "cp", Path: dst, Err: errors.New("destination is not a directory")}
}
for _, arg := range args[:len(args)-1] {
var (
src string
data []byte
mode fs.FileMode
)
switch arg {
case "stdout":
src = arg
data = []byte(s.Stdout())
mode = 0666
case "stderr":
src = arg
data = []byte(s.Stderr())
mode = 0666
default:View on GitHub (pinned to b6b368adc5)
Solutions
- Precede the cp with `mkdir out/` (or the Mkdir command) so the destination directory exists.
- Reduce to a two-argument cp if you intend file-to-file copy: `cp a.txt b.txt`.
- Check the destination path spelling in the script line.
- If the directory exists, verify the script's working dir (script.WorkDir / cd) matches where you expect it.
Example fix
// before (script.txt) cp a.txt b.txt out/ # -> cp out/: destination is not a directory // after mkdir out/ cp a.txt b.txt out/
Defensive patterns
Strategy: validation
Validate before calling
// Before cp, ensure the multi-source destination is an existing dir.
func ensureCpDest(args ...string) error {
if len(args) <= 2 { return nil }
info, err := os.Stat(args[len(args)-1])
if err != nil || !info.IsDir() {
return fmt.Errorf("%s is not a directory", args[len(args)-1])
}
return nil
} Type guard
func isDestNotDir(err error) bool {
var pe *fs.PathError
return errors.As(err, &pe) && pe.Op == "cp" && pe.Err != nil &&
strings.Contains(pe.Err.Error(), "destination is not a directory")
} Try / catch
// In a script test, mkdir first; the engine surfaces the PathError directly. mkdir out/ cp a.txt b.txt out/
Prevention
- Always mkdir the destination directory before a multi-source cp in script tests.
- Use a two-argument cp for file-to-file copies.
- Keep script working directories explicit (cd) so dest paths resolve as expected.
When it happens
Trigger: Writing a script-test line like `cp a.txt b.txt dir/` where 'dir/' does not exist or is a regular file. Cp is invoked with len(args) > 2, os.Stat(dst) either errors or returns a non-directory, so dstDir is false and the PathError is returned before any source is read.
Common situations: Script-test author forgets to `mkdir` the target directory first, or typos the destination name, or points at a file that should have been a directory. Also when copying stdout/stderr plus a file into a non-existent dir: `cp stdout a.txt out/`.
Related errors
- no engine configured
- duplicated '!' or '?' token
- empty condition
- empty command
- unterminated quoted argument
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/65160adf0ff8d733.
Report an issue: GitHub.