gohugoio/hugo · error
failed to open dir
Error message
failed to open dir %q: %q
What it means
mountCommonJSConfig opens owner.Dir() with c.fs.Open to scan for JS config files (babel/postcss/tailwind.config.js, package.hugo.json); if the open fails for a reason other than not-exist (which is tolerated elsewhere), the raw error is surfaced. Indicates a filesystem/permission problem on an already-resolved module directory.
Solutions
- Check permissions on the dir named in the error: `ls -ld <dir>` and chmod/chown as needed.
- Resolve broken symlinks inside the module/theme dir.
- For cache dirs, `go clean -modcache` then rebuild to restore a clean tree.
- In containers, confirm the volume mount actually includes the module dir.
Example fix
// before: theme dir not readable chmod -R go-rx themes/mytheme // after: restore read+execute on the dir chmod -R a+rX themes/mytheme
Defensive patterns
Strategy: validation
Validate before calling
// Ensure module/theme dirs are openable before build
func ensureDirOpenable(dir string) error {
f, err := os.Open(dir)
if err != nil { return fmt.Errorf("cannot open %s: %w", dir, err) }
return f.Close()
} Type guard
null
Try / catch
// if errors.Is(err, fs.ErrPermission) { chmod + retry } Prevention
- Set read+execute perms on theme/module dirs in setup.
- Avoid broken symlinks in theme trees.
- In containers, mount module/theme dirs readably.
When it happens
Trigger: A module whose Dir() exists in metadata but cannot be opened — permission denied, symlink loop, removed between resolution and scan, or an afero filesystem layer rejecting the open.
Common situations: Permission drift on the module cache/theme dir, a broken symlink in a theme, network filesystem hiccup, or a container mount that omits the dir.
Related errors
- %s: %q
- failed to copy config dir to vendor dir
- failed to copy module file to vendor
- failed to copy module to vendor dir
- failed to copy resources to vendor dir
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/fdbc67fb73d7e5aa.
Report an issue: GitHub.
Appendix: source
Thrown at modules/collect.go:674
}
// Matches postcss.config.js etc.
var commonJSConfigs = regexp.MustCompile(`^(babel|postcss|tailwind)\.config\.(c|m)?js$`)
func (c *collector) mountCommonJSConfig(owner *moduleAdapter, mounts []Mount) ([]Mount, error) {
for _, m := range mounts {
if strings.HasPrefix(m.Target, files.JsConfigFolderMountPrefix) {
// This follows the convention of the other component types (assets, content, etc.),
// if one or more is specified by the user, we skip the defaults.
// These mounts were added to Hugo in 0.75.
return mounts, nil
}
}
// Mount the common JS config files.
d, err := c.fs.Open(owner.Dir())
if err != nil {
return mounts, fmt.Errorf("failed to open dir %q: %q", owner.Dir(), err)
}
defer d.Close()
fis, err := d.(fs.ReadDirFile).ReadDir(-1)
if err != nil {
return mounts, fmt.Errorf("failed to read dir %q: %q", owner.Dir(), err)
}
hasPackageHugoJSON := false
for _, fi := range fis {
if fi.Name() == files.FilenamePackageHugoJSON {
hasPackageHugoJSON = true
break
}
}
for _, fi := range fis {
n := fi.Name()
View on GitHub (pinned to 52c9bd7908)