golang/go · error · fs.PathError

overlay maps to directory

Error message

overlay maps to directory

What it means

When stat'ing an overlaid path (one whose info.replaced is true), the target file on disk is found to be a directory. The overlay always stats through symlinks (using Stat, not Lstat), so if a symlink target resolves to a directory, it is treated the same as a direct directory mapping and rejected. This keeps the data model simple: overlay targets must be regular files.

Source

Thrown at src/cmd/go/internal/fsys/fsys.go:660

	info := stat(path)
	if info.deleted {
		return nil, &fs.PathError{Op: op, Path: path, Err: fs.ErrNotExist}
	}
	if info.dir {
		return fakeDir(filepath.Base(path)), nil
	}
	if info.replaced {
		// To keep the data model simple, if the overlay contains a symlink we
		// always stat through it (using Stat, not Lstat). That way we don't need to
		// worry about the interaction between Lstat and directories: if a symlink
		// in the overlay points to a directory, we reject it like an ordinary
		// directory.
		ainfo, err := os.Stat(info.actual)
		if err != nil {
			return nil, err
		}
		if ainfo.IsDir() {
			return nil, &fs.PathError{Op: op, Path: path, Err: fmt.Errorf("overlay maps to directory")}
		}
		return fakeFile{name: filepath.Base(path), real: ainfo}, nil
	}
	return osStat(path)
}

// fakeFile provides an fs.FileInfo implementation for an overlaid file,
// so that the file has the name of the overlaid file, but takes all
// other characteristics of the replacement file.
type fakeFile struct {
	name string
	real fs.FileInfo
}

func (f fakeFile) Name() string       { return f.name }
func (f fakeFile) Size() int64        { return f.real.Size() }
func (f fakeFile) Mode() fs.FileMode  { return f.real.Mode() }
func (f fakeFile) ModTime() time.Time { return f.real.ModTime() }

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Look at the overlay entry for the path in the error message and verify its target is a regular file.
  2. If the target is a symlink, check what it resolves to — it must not be a directory.
  3. Replace the target path so it points to a specific regular file.
  4. Remove the overlay entry entirely if the path should be a directory on disk.
Defensive patterns

Strategy: validation

Validate before calling

// Check overlay targets including symlink resolution for directory targets.
func validateOverlayStatTargets(entries map[string]string) error {
    for from, to := range entries {
        if to == "" {
            continue
        }
        info, err := os.Stat(to) // follows symlinks
        if err != nil {
            continue
        }
        if info.IsDir() {
            return fmt.Errorf("overlay target %s resolves to directory %s", from, to)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Calling fsys.Stat or fsys.Lstat on a path that has a replacement in the overlay, where the replacement target (info.actual) is a directory or a symlink resolving to a directory. The overlayStat function detects ainfo.IsDir()==true and returns this error.

Common situations: Overlay JSON points a file replacement at a directory path. A symlink target in the overlay was once a file but became a directory (e.g., after a git branch switch). Overlay generated from a different filesystem layout where the target structure changed.

Related errors


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