gohugoio/hugo · error
could not determine content directory for %q
Error message
could not determine content directory for %q
What it means
`BaseFs.AbsProjectContentDir` maps a content filename (as given to `hugo new`) to an absolute path inside one of the project's content mounts. If the name doesn't fall under any configured content mount and no project-owned content directory exists to place it in, Hugo cannot decide where the file belongs and returns this error.
Source
Thrown at hugolib/filesystems/basefs.go:210
}
if !isAbs {
// A filename on the form "posts/mypage.md", put it inside
// the first content folder, usually <workDir>/content.
// Pick the first project dir (which is probably the most important one).
for _, dir := range b.SourceFilesystems.Content.mounts() {
if !dir.IsDir() {
continue
}
meta := dir.Meta()
if meta.IsProject {
return filename, filepath.Join(meta.Filename, filename), nil
}
}
}
return "", "", fmt.Errorf("could not determine content directory for %q", filename)
}
// ResolveJSConfigFile resolves the JS-related config file to a absolute
// filename. One example of such would be postcss.config.js.
func (b *BaseFs) ResolveJSConfigFile(name string) string {
// First look in assets/_jsconfig
fi, err := b.Assets.Fs.Stat(filepath.Join(files.FolderJSConfig, name))
if err == nil {
return fi.(hugofs.FileMetaInfo).Meta().Filename
}
// Fall back to the work dir.
fi, err = b.Work.Stat(name)
if err == nil {
return fi.(hugofs.FileMetaInfo).Meta().Filename
}
return ""
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Run the command from the site root and ensure the `content/` directory (or your configured `contentDir`) exists — `mkdir content` fixes the fresh-site case.
- If you use `[[module.mounts]]`, add a project mount with `source = "content"` and `target = "content"` so there's a project content dir to receive new files.
- Pass a path that resolves inside an existing content mount, e.g. `hugo new content posts/first.md` rather than an absolute path outside the project.
Example fix
# before (hugo.toml with custom mounts, no project content mount) [[module.mounts]] source = "themes/x/content" target = "content" # after [[module.mounts]] source = "content" target = "content" [[module.mounts]] source = "themes/x/content" target = "content"
Defensive patterns
Strategy: validation
Validate before calling
# Verify the target directory maps into a configured content mount:
hugo config mounts | jq '.[] | select(.target|startswith("content"))'
# Ensure the path you create/reference lives under one of those source dirs Try / catch
if err := createContent(path); err != nil {
return fmt.Errorf("path %q is outside all content mounts — add a [[module.mounts]] entry or use contentDir: %w", path, err)
} Prevention
- When using module mounts, ensure every content path you write to is covered by a mount targeting content
- Use `hugo new` with paths relative to the content dir, not absolute filesystem paths
- After editing [[module.mounts]], run `hugo config mounts` to confirm the mapping
- Don't mix a custom contentDir with mounts unless both are declared
When it happens
Trigger: Running `hugo new content posts/my-page.md` (or the archetype machinery) when the resolved path matches no content mount: the `content` directory is missing, all content mounts come from themes/modules (none has `IsProject`), or an absolute/target path lies outside every configured `[[module.mounts]]` source for the content component.
Common situations: Running `hugo new` from the wrong working directory (not the site root); a config using `[[module.mounts]]` that remaps content but forgets a project-level content mount; brand-new sites where `content/` was never created; `contentDir` pointing at a non-existent path.
Related errors
- failed to save file %q:: %w
- failed to resolve output path %q: %w
- failed to copy %q to %q: %w
- target path "%s" exists but is not a directory
- failed to save file %q: %s
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/b4dfcd3fc423140d.json.
Report an issue: GitHub ↗.