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
- Look at the overlay entry for the path in the error message and verify its target is a regular file.
- If the target is a symlink, check what it resolves to — it must not be a directory.
- Replace the target path so it points to a specific regular file.
- 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
- Stat (not Lstat) overlay targets to check they are not directories.
- Verify symlinks in overlay targets do not resolve to directories.
- Run a pre-build validation script on the overlay JSON.
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
- inconsistent files %s and %s in overlay map
- overlay maps child %s to directory
- total length of command line and environment variables excee
- deleted in overlay
- cannot open directory in overlay
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/3e259487d3f96fb5.
Report an issue: GitHub.