{"record":{"id":"3c156b16026cda5e","repo":"gohugoio/hugo","slug":"failed-to-read-dir-q-q","errorCode":null,"errorMessage":"failed to read dir %q: %q","messagePattern":"failed to read dir %q: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/collect.go","lineNumber":679,"sourceCode":"func (c *collector) mountCommonJSConfig(owner *moduleAdapter, mounts []Mount) ([]Mount, error) {\n\tfor _, m := range mounts {\n\t\tif strings.HasPrefix(m.Target, files.JsConfigFolderMountPrefix) {\n\t\t\t// This follows the convention of the other component types (assets, content, etc.),\n\t\t\t// if one or more is specified by the user, we skip the defaults.\n\t\t\t// These mounts were added to Hugo in 0.75.\n\t\t\treturn mounts, nil\n\t\t}\n\t}\n\n\t// Mount the common JS config files.\n\td, err := c.fs.Open(owner.Dir())\n\tif err != nil {\n\t\treturn mounts, fmt.Errorf(\"failed to open dir %q: %q\", owner.Dir(), err)\n\t}\n\tdefer d.Close()\n\tfis, err := d.(fs.ReadDirFile).ReadDir(-1)\n\tif err != nil {\n\t\treturn mounts, fmt.Errorf(\"failed to read dir %q: %q\", owner.Dir(), err)\n\t}\n\n\thasPackageHugoJSON := false\n\tfor _, fi := range fis {\n\t\tif fi.Name() == files.FilenamePackageHugoJSON {\n\t\t\thasPackageHugoJSON = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\tfor _, fi := range fis {\n\t\tn := fi.Name()\n\n\t\tshould := n == files.FilenamePackageHugoJSON || (n == files.FilenamePackageJSON && !hasPackageHugoJSON)\n\t\tshould = should || commonJSConfigs.MatchString(n)\n\n\t\tif should {\n\t\t\tmounts = append(mounts, Mount{","sourceCodeStart":661,"sourceCodeEnd":697,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/modules/collect.go#L661-L697","documentation":"Immediately after opening owner.Dir() succeeds, mountCommonJSConfig calls ReadDir(-1) on it; if reading entries fails (directory deleted mid-call, I/O error, permission revoked between open and read), the raw error is wrapped here. Distinct from 475 in that the directory was openable but unreadable.","triggerScenarios":"The directory fd opened but readdir failed — dir removed between Open and ReadDir (race), filesystem I/O error, NFS/server hiccup, or the fd refers to something that is no longer a readable directory.","commonSituations":"Concurrent process deleting/renaming the module dir during build, network filesystem transient errors, SELinux denying readdir but allowing open, or a corrupt directory entry.","solutions":["Re-run the build (transient FS/IO errors often clear); if persistent, investigate the underlying volume.","Ensure no concurrent job removes the module/theme dir during the build.","For network filesystems, check connectivity/mount health and remount if stale.","Verify directory integrity: `ls -la <dir>`; if it errors, re-fetch the module/theme."],"exampleFix":"// before: stale NFS mount during build\n// after: remount and re-fetch\nmount -o remount /srv/modules\ngo clean -modcache && hugo","handlingStrategy":"retry","validationCode":"// Read-dir probe with one retry to absorb transient FS errors\nfunc readDirSafe(dir string) ([]os.DirEntry, error) {\n  entries, err := os.ReadDir(dir)\n  if err != nil {\n    time.Sleep(100 * time.Millisecond)\n    return os.ReadDir(dir)\n  }\n  return entries, nil\n}","typeGuard":"null","tryCatchPattern":"// Treat transient readdir errors as retryable; persistent ones as environment faults.","preventionTips":["Don't delete module dirs concurrently with builds.","Keep network FS mounts healthy; remount stale ones.","Retry once on transient IO before failing the build."],"tags":["modules","filesystem","io","hugo-module"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}