{"record":{"id":"6af1f23741fe0f90","repo":"golang/go","slug":"cannot-open-directory-in-overlay","errorCode":null,"errorMessage":"cannot open directory in overlay","messagePattern":"cannot open directory in overlay","errorType":"exception","errorClass":"fs.PathError","httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/fsys/fsys.go","lineNumber":567,"sourceCode":"// Open opens the named file in the virtual file system.\n// It must be an ordinary file, not a directory.\nfunc Open(name string) (*os.File, error) {\n\tTrace(\"Open\", name)\n\n\tbad := func(msg string) (*os.File, error) {\n\t\treturn nil, &fs.PathError{\n\t\t\tOp:   \"Open\",\n\t\t\tPath: name,\n\t\t\tErr:  errors.New(msg),\n\t\t}\n\t}\n\n\tinfo := stat(name)\n\tif info.deleted {\n\t\treturn bad(\"deleted in overlay\")\n\t}\n\tif info.dir {\n\t\treturn bad(\"cannot open directory in overlay\")\n\t}\n\tif info.replaced {\n\t\tname = info.actual\n\t}\n\n\treturn os.Open(name)\n}\n\n// ReadFile reads the named file from the virtual file system\n// and returns the contents.\nfunc ReadFile(name string) ([]byte, error) {\n\tf, err := Open(name)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\n\treturn io.ReadAll(f)","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/fsys/fsys.go#L549-L585","documentation":"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().","triggerScenarios":"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'.","commonSituations":"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.","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"],"exampleFix":"// before: Open called on a directory path\n// f, err := fsys.Open(\"src/mypackage\")\n// // error: cannot open directory in overlay\n\n// after: use ReadDir for directories, Open for files\n// entries, err := fsys.ReadDir(\"src/mypackage\")\n// for _, e := range entries {\n//     if !e.IsDir() {\n//         f, err := fsys.Open(filepath.Join(\"src/mypackage\", e.Name()))\n//         // ...\n//     }\n// }","handlingStrategy":"validation","validationCode":"// Before calling Open, check whether the path is a directory.\nimport \"os\"\n\nfunc safeOpen(fs *OverlayFS, path string) (*os.File, error) {\n    info, err := os.Stat(path)\n    if err != nil {\n        return nil, err\n    }\n    if info.IsDir() {\n        return nil, fmt.Errorf(\"%s is a directory, use ReadDir instead\", path)\n    }\n    return fs.Open(path)\n}","typeGuard":"// The error is returned as *fs.PathError with Op=\"Open\".\nimport \"io/fs\"\n\nfunc isOverlayDirError(err error) bool {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) {\n        return pathErr.Op == \"Open\" && strings.Contains(pathErr.Err.Error(), \"cannot open directory\")\n    }\n    return false\n}","tryCatchPattern":"// file, err := fsys.Open(path)\n// if err != nil {\n//     if isOverlayDirError(err) {\n//         // It's a directory — use ReadDir instead\n//         entries, err := fsys.ReadDir(path)\n//         if err != nil {\n//             return err\n//         }\n//         for _, e := range entries {\n//             // process each entry\n//         }\n//         return nil\n//     }\n//     return err\n// }\n// defer file.Close()","preventionTips":["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"],"tags":["go","overlay","filesystem","virtual-fs","api-misuse"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}