{"id":"fdbc67fb73d7e5aa","repo":"gohugoio/hugo","slug":"failed-to-open-dir-q-q","errorCode":null,"errorMessage":"failed to open dir %q: %q","messagePattern":"failed to open dir %q: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/collect.go","lineNumber":674,"sourceCode":"}\n\n// Matches postcss.config.js etc.\nvar commonJSConfigs = regexp.MustCompile(`^(babel|postcss|tailwind)\\.config\\.(c|m)?js$`)\n\nfunc (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","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/modules/collect.go#L656-L692","documentation":"`mountCommonJSConfig` (modules/collect.go:674) auto-mounts JS tooling configs (`postcss.config.js`, `babel.config.js`, `tailwind.config.js`, `package.hugo.json`) from a module's root when the user hasn't mounted them explicitly. To do so it opens the module's directory; if `Open` fails, Hugo reports `failed to open dir %q: %q` with the directory and underlying error.","triggerScenarios":"Module collection calling `c.fs.Open(owner.Dir())` on a module whose resolved root directory can't be opened — deleted after resolution, permission denied, or a path that exists as a file rather than a directory (e.g. broken replacement mapping).","commonSituations":"Restrictive permissions on Go module cache dirs (the cache is read-only, but ACL/umask oddities or containers mounting it wrong can break reads); a `module.replacements` target pointing at a file; network/overlay filesystems dropping the directory mid-build.","solutions":["Check the quoted directory exists and is readable: `ls -la <dir>`.","If it's under the Go module cache and corrupted, run `hugo mod clean` (or `go clean -modcache`) and re-download.","Fix any `module.replacements` entry pointing at a file or nonexistent path.","In containers, ensure the module cache volume is mounted with read access for the build user."],"exampleFix":"# before: cache dir unreadable in container\ndocker run -v gocache:/root/go ... hugo\n# after: fix ownership/permissions\ndocker run -v gocache:/root/go -u root ... sh -c 'chmod -R a+rX /root/go/pkg/mod && hugo'","handlingStrategy":"validation","validationCode":"if fi, err := os.Stat(dir); err != nil {\n    return fmt.Errorf(\"dir %q missing: %w\", dir, err)\n} else if !fi.IsDir() {\n    return fmt.Errorf(\"%q is not a directory\", dir)\n}","typeGuard":"func isPermOrNotExist(err error) bool {\n    return errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission)\n}","tryCatchPattern":"if err := walk(dir); err != nil {\n    if errors.Is(err, fs.ErrPermission) { /* fix perms, don't retry */ }\n    return err\n}","preventionTips":["Ensure directories referenced by modules/mounts exist with read permission for the build user","In containers, check volume mounts and ownership (UID mapping) for module cache dirs","Avoid symlinks pointing outside the allowed workspace — Hugo's security model may block them"],"tags":["hugo-modules","filesystem","permissions","js-config"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}