golang/go · error

build output %q already exists and is a directory

Error message

build output %q already exists and is a directory

What it means

Thrown by checkDstOverwrite when the requested build output path (`go build -o <path>`) already exists and is a directory. The go command refuses to overwrite/remove a directory to avoid destroying data, regardless of the -f/force setting.

Source

Thrown at src/cmd/go/internal/work/shell.go:253

}

// mayberemovefile removes a file only if it is a regular file
// When running as a user with sufficient privileges, we may delete
// even device files, for example, which is not intended.
func mayberemovefile(s string) {
	if fi, err := os.Lstat(s); err == nil && !fi.Mode().IsRegular() {
		return
	}
	os.Remove(s)
}

// Be careful about removing/overwriting dst.
// Do not remove/overwrite if dst exists and is a directory
// or a non-empty non-object file.
func checkDstOverwrite(dst string, force bool) error {
	if fi, err := os.Stat(dst); err == nil {
		if fi.IsDir() {
			return fmt.Errorf("build output %q already exists and is a directory", dst)
		}
		if !force && fi.Mode().IsRegular() && fi.Size() != 0 && !isObject(dst) {
			return fmt.Errorf("build output %q already exists and is not an object file", dst)
		}
	}
	return nil
}

// writeFile writes the text to file.
func (sh *Shell) writeFile(file string, text []byte) error {
	if cfg.BuildN || cfg.BuildX {
		switch {
		case len(text) == 0:
			sh.ShowCmd("", "echo -n > %s # internal", file)
		case bytes.IndexByte(text, '\n') == len(text)-1:
			// One line. Use a simpler "echo" command.
			sh.ShowCmd("", "echo '%s' > %s # internal", bytes.TrimSuffix(text, []byte("\n")), file)
		default:

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Pick a different output name: `go build -o myapp-bin`.
  2. Remove or rename the existing directory: `rmdir myapp` (only if empty/unused).
  3. Build into the directory explicitly with a file path: `go build -o ./bin/myapp`.

Example fix

# before
// mkdir myapp && go build -o myapp

# after
// go build -o ./bin/myapp
Defensive patterns

Strategy: validation

Validate before calling

// Ensure -o target is not an existing directory
out := flag.Arg(0)
if fi, err := os.Stat(out); err == nil && fi.IsDir() {
    log.Fatalf("%s is a directory; choose a file path", out)
}

Prevention

When it happens

Trigger: Run `go build -o myapp` where `myapp` is an existing directory (e.g. you forgot the trailing slash, or a directory was created earlier by `mkdir myapp`). os.Stat reports IsDir, and checkDstOverwrite returns immediately.

Common situations: Typo where `-o app` collides with a source/module directory named `app`; CI that pre-creates an output directory; a previous `go build -o ./out` followed by `go build -o ./out` after `./out` became a folder; mirroring a Makefile target name that is also a dir.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/440903b382dcefe9. Report an issue: GitHub.