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

  1. Use ReadDir() or fsys.ReadDir() instead of Open() when you need to list directory contents
  2. Ensure the path argument to Open() points to a specific file, not a directory
  3. Check the path construction logic for trailing slashes, missing file extensions, or missing filenames
  4. 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

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


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