gohugoio/hugo · error
must resolve to an absolute directory
Error message
%q must resolve to an absolute directory
What it means
After resolving placeholders, DecodeConfig checks that non-resource cache dirs on the real OS filesystem resolve to an absolute path (filecache_config.go:276-278). Hugo requires absolute paths because it performs file eviction/removal and a relative base could be unsafe or ambiguous depending on the working directory.
Solutions
- Use an absolute path for the cache dir (e.g. /home/user/.cache/hugo)
- Use the :cacheDir placeholder which Hugo resolves to an absolute location
- Pass --cacheDir /absolute/path on the command line
Example fix
# before cacheDir = "./mycache" # after cacheDir = "/home/user/.cache/hugo"
Defensive patterns
Strategy: validation
Validate before calling
// Ensure cacheDir is absolute before running Hugo.
func ensureAbsCacheDir(dir string) string {
if !filepath.IsAbs(dir) {
abs, _ := filepath.Abs(dir)
return abs
}
return dir
} Prevention
- Always use absolute paths for cacheDir in config
- Use the :cacheDir placeholder which Hugo resolves absolutely
- Avoid relative paths in shared/committed config files
When it happens
Trigger: Setting a cache's dir (or cacheDir) to a relative path like "./cache" or "my-cache" while running on the OS filesystem.
Common situations: Relative paths in config files; running Hugo from varying working directories; portable config that works on one machine but not another.
Related errors
- is a root folder and not allowed as cache dir
- cache dir contains unresolved placeholders
- failed to decode filecache config
- is not a valid cache name
- is not a valid placeholder (valid values are :cacheDir or…
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/21824f43a0ec4122.
Report an issue: GitHub.
Appendix: source
Thrown at cache/filecache/filecache_config.go:278
if err != nil {
return c, err
}
if isResource {
v.IsResourceDir = true
}
parts[i] = resolved
}
}
dir = path.Join(parts...)
if hadSlash {
dir = "/" + dir
}
v.DirCompiled = filepath.Clean(filepath.FromSlash(dir))
if !v.IsResourceDir {
if isOsFs && !filepath.IsAbs(v.DirCompiled) {
return c, fmt.Errorf("%q must resolve to an absolute directory", v.DirCompiled)
}
// Avoid cache in root, e.g. / (Unix) or c:\ (Windows)
if len(strings.TrimPrefix(v.DirCompiled, filepath.VolumeName(v.DirCompiled))) == 1 {
return c, fmt.Errorf("%q is a root folder and not allowed as cache dir", v.DirCompiled)
}
}
if !strings.HasPrefix(v.DirCompiled, "_gen") {
// We do cache eviction (file removes) and since the user can set
// his/hers own cache directory, we really want to make sure
// we do not delete any files that do not belong to this cache.
// We do add the cache name as the root, but this is an extra safe
// guard. We skip the files inside /resources/_gen/ because
// that would be breaking.
v.DirCompiled = filepath.Join(v.DirCompiled, FilecacheRootDirname, k)
} else {
v.DirCompiled = filepath.Join(v.DirCompiled, k)View on GitHub (pinned to 52c9bd7908)