golang/go · error · fs.PathError
cannot open directory in overlay
Error message
cannot open directory in overlay
What it means
The overlay filesystem's Open() function was called on a path that stat() identified as a directory. Open() only opens regular files — it cannot return a file handle for a directory. This is a fundamental API restriction: directory listings require ReadDir() or fsys.ReadDir(), not Open().
Source
Thrown at src/cmd/go/internal/fsys/fsys.go:567
// Open opens the named file in the virtual file system.
// It must be an ordinary file, not a directory.
func Open(name string) (*os.File, error) {
Trace("Open", name)
bad := func(msg string) (*os.File, error) {
return nil, &fs.PathError{
Op: "Open",
Path: name,
Err: errors.New(msg),
}
}
info := stat(name)
if info.deleted {
return bad("deleted in overlay")
}
if info.dir {
return bad("cannot open directory in overlay")
}
if info.replaced {
name = info.actual
}
return os.Open(name)
}
// ReadFile reads the named file from the virtual file system
// and returns the contents.
func ReadFile(name string) ([]byte, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)View on GitHub (pinned to b6b368adc5)
Solutions
- Use ReadDir() or fsys.ReadDir() instead of Open() when you need to list directory contents
- Ensure the path argument to Open() points to a specific file, not a directory
- Check the path construction logic for trailing slashes, missing file extensions, or missing filenames
- Add a pre-check using os.Stat or fsys.Stat to verify the path is a file before calling Open
Example fix
// before: Open called on a directory path
// f, err := fsys.Open("src/mypackage")
// // error: cannot open directory in overlay
// after: use ReadDir for directories, Open for files
// entries, err := fsys.ReadDir("src/mypackage")
// for _, e := range entries {
// if !e.IsDir() {
// f, err := fsys.Open(filepath.Join("src/mypackage", e.Name()))
// // ...
// }
// } Defensive patterns
Strategy: validation
Validate before calling
// Before calling Open, check whether the path is a directory.
import "os"
func safeOpen(fs *OverlayFS, path string) (*os.File, error) {
info, err := os.Stat(path)
if err != nil {
return nil, err
}
if info.IsDir() {
return nil, fmt.Errorf("%s is a directory, use ReadDir instead", path)
}
return fs.Open(path)
} Type guard
// The error is returned as *fs.PathError with Op="Open".
import "io/fs"
func isOverlayDirError(err error) bool {
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
return pathErr.Op == "Open" && strings.Contains(pathErr.Err.Error(), "cannot open directory")
}
return false
} Try / catch
// file, err := fsys.Open(path)
// if err != nil {
// if isOverlayDirError(err) {
// // It's a directory — use ReadDir instead
// entries, err := fsys.ReadDir(path)
// if err != nil {
// return err
// }
// for _, e := range entries {
// // process each entry
// }
// return nil
// }
// return err
// }
// defer file.Close() Prevention
- Always check os.Stat().IsDir() before calling Open if the path type is uncertain
- Use ReadDir() or fsys.ReadDir() for directory listings, never Open()
- Validate path construction logic to ensure file extensions are present
- Add path validation in build tooling that constructs file paths dynamically
When it happens
Trigger: OverlayFS.Open(name) calls stat(name) which returns info.dir=true. The path resolves to a directory in the virtual filesystem (either real or overlaid). Open returns a PathError with 'cannot open directory in overlay'.
Common situations: Code tries to Open() a package directory path instead of a specific .go file; a glob or walk routine mistakenly calls Open on a directory path; incorrect path construction in build tooling that omits the filename; a configuration error passing a directory where a file path is expected.
Related errors
- deleted in overlay
- Go.run: WebAssembly.Instance expected
- file is empty
- inode for file changed since last Lock or RLock
- ed25519: expected opts.HashFunc() zero (unhashed message, fo
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/6af1f23741fe0f90.
Report an issue: GitHub.