apache/answer · error

failed to create directory %s: %w

Error message

failed to create directory %s: %w

What it means

Inside copyDirEntries' fs.WalkDir callback, for every directory entry the destination directory is created with os.MkdirAll(dstPath, os.ModePerm). This error wraps a failed MkdirAll for the destination path — the target directory could not be created (or an intermediate parent exists as a file). It is the first failure point of any directory copy done by the build (UI files, plugins, vendor moves).

Source

Thrown at internal/cli/build.go:530

		if ignoreThisDir(path) {
			return nil
		}

		// Convert the path to use forward slashes, important because we use embedded FS which always uses forward slashes
		path = filepath.ToSlash(path)

		// Construct the absolute path for the source file/directory
		srcPath := filepath.Join(sourceDir, path)
		srcPath = filepath.ToSlash(srcPath)

		// Construct the absolute path for the destination file/directory
		dstPath := filepath.Join(targetDir, path)

		if d.IsDir() {
			// Create the directory in the destination
			err := os.MkdirAll(dstPath, os.ModePerm)
			if err != nil {
				return fmt.Errorf("failed to create directory %s: %w", dstPath, err)
			}
		} else {
			// Open the source file
			srcFile, err := sourceFs.Open(srcPath)
			if err != nil {
				return fmt.Errorf("failed to open source file %s: %w", srcPath, err)
			}
			defer srcFile.Close()

			// Create the destination file
			dstFile, err := os.Create(dstPath)
			if err != nil {
				return fmt.Errorf("failed to create destination file %s: %w", dstPath, err)
			}
			defer dstFile.Close()

			// Copy the file contents
			_, err = io.Copy(dstFile, srcFile)

View on GitHub (pinned to 3b9f137061)

Solutions

  1. Look at the wrapped %w cause and the %s path: if a file exists where a directory is needed, delete that stale file and re-run.
  2. Ensure the build user has write permission on the target parent directory (`chmod u+w` / run as the directory owner).
  3. Free disk space or raise the quota on the volume holding the build tmp dir.
  4. Clear the whole tmp build directory and rebuild from scratch to eliminate leftovers from prior failed runs.

Example fix

// caller-side prevention: start from a clean target
os.RemoveAll(targetDir)
os.MkdirAll(targetDir, os.ModePerm)
err := copyDirEntries(os.DirFS(src), ".", targetDir, "node_modules")
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Lstat(targetDir); err == nil && !fi.IsDir() {
	return fmt.Errorf("%s exists and is not a directory; remove it", targetDir)
}
parent := filepath.Dir(targetDir)
probe := filepath.Join(parent, ".mkdir-probe")
if err := os.WriteFile(probe, nil, 0o600); err != nil {
	return fmt.Errorf("cannot write to %s: %w", parent, err)
}
os.Remove(probe)

Type guard

func canMkdir(target string) bool {
	// true if target is absent (creatable) or already a directory
	fi, err := os.Lstat(target)
	if err != nil { return errors.Is(err, os.ErrNotExist) }
	return fi.IsDir()
}

Try / catch

var perr *fs.PathError
err := copyDirEntries(sourceFs, sourceDir, targetDir, "node_modules")
if errors.As(err, &perr) && errors.Is(perr.Err, syscall.ENOTDIR) {
	os.RemoveAll(perr.Path) // stale file where a dir is needed
	err = copyDirEntries(sourceFs, sourceDir, targetDir, "node_modules")
}
if err != nil {
	log.Printf("mkdir/copy failed: %v — check permissions and disk space on %s", err, targetDir)
}
return err

Prevention

When it happens

Trigger: os.MkdirAll(dstPath, os.ModePerm) fails during a WalkDir over the source FS: destination parent path exists as a regular file, EACCES/EACCES-like permission denial on the target volume, ENOSPC or filesystem errors, or an overly long path.

Common situations: Previous build left a file where this build expects to create a directory (classic ENOTDIR); running the build in a read-only container layer or as a non-privileged user; tmp dir on a full/quota-limited disk; copying a dir tree whose deep paths exceed the filesystem's NAME_MAX/path limits.

Related errors


AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05). Data as JSON: /api/errors/4c83eda56d45fd99. Report an issue: GitHub.