{"id":"34cb46e9ea404f0d","repo":"gohugoio/hugo","slug":"q-is-a-root-folder-and-not-allowed-as-cache-dir","errorCode":null,"errorMessage":"%q is a root folder and not allowed as cache dir","messagePattern":"%q is a root folder and not allowed as cache dir","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cache/filecache/filecache_config.go","lineNumber":283,"sourceCode":"\t\t\t\t}\n\t\t\t\tparts[i] = resolved\n\t\t\t}\n\t\t}\n\n\t\tdir = path.Join(parts...)\n\t\tif hadSlash {\n\t\t\tdir = \"/\" + dir\n\t\t}\n\t\tv.DirCompiled = filepath.Clean(filepath.FromSlash(dir))\n\n\t\tif !v.IsResourceDir {\n\t\t\tif isOsFs && !filepath.IsAbs(v.DirCompiled) {\n\t\t\t\treturn c, fmt.Errorf(\"%q must resolve to an absolute directory\", v.DirCompiled)\n\t\t\t}\n\n\t\t\t// Avoid cache in root, e.g. / (Unix) or c:\\ (Windows)\n\t\t\tif len(strings.TrimPrefix(v.DirCompiled, filepath.VolumeName(v.DirCompiled))) == 1 {\n\t\t\t\treturn c, fmt.Errorf(\"%q is a root folder and not allowed as cache dir\", v.DirCompiled)\n\t\t\t}\n\t\t}\n\n\t\tif !strings.HasPrefix(v.DirCompiled, \"_gen\") {\n\t\t\t// We do cache eviction (file removes) and since the user can set\n\t\t\t// his/hers own cache directory, we really want to make sure\n\t\t\t// we do not delete any files that do not belong to this cache.\n\t\t\t// We do add the cache name as the root, but this is an extra safe\n\t\t\t// guard. We skip the files inside /resources/_gen/ because\n\t\t\t// that would be breaking.\n\t\t\tv.DirCompiled = filepath.Join(v.DirCompiled, FilecacheRootDirname, k)\n\t\t} else {\n\t\t\tv.DirCompiled = filepath.Join(v.DirCompiled, k)\n\t\t}\n\n\t\tc[k] = v\n\t}\n","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/cache/filecache/filecache_config.go#L265-L301","documentation":"Returned by filecache.DecodeConfig when a cache directory compiles to a filesystem root such as `/` on Unix or `C:\\` on Windows (path length 1 after stripping the volume name). Hugo prunes and deletes files inside cache directories, so allowing a root directory could lead to catastrophic deletion; this is an explicit safety guard.","triggerScenarios":"caches.<name>.dir set to `/`, `C:\\`, or a placeholder chain that collapses to root — e.g. `:cacheDir` when the configured cacheDir is `/`, or `dir = \"/..\"`-style paths that Clean to `/`.","commonSituations":"Misconfigured HUGO_CACHEDIR or cacheDir set to `/` in containers, env substitution yielding just a slash, or Docker setups mounting a cache volume at root and pointing Hugo directly at it.","solutions":["Point the cache dir at a dedicated subdirectory, e.g. `/var/cache/hugo` or `/tmp/hugo_cache`, never the filesystem root.","Check the top-level cacheDir setting and HUGO_CACHEDIR env var for values like `/`.","In containers, mount the cache volume at a subpath (e.g. /cache) and set cacheDir to that."],"exampleFix":"# before\nHUGO_CACHEDIR=/ hugo\n# after\nHUGO_CACHEDIR=/var/cache/hugo hugo","handlingStrategy":"validation","validationCode":"clean := filepath.Clean(resolvedDir)\nif clean == string(os.PathSeparator) || (len(clean) == 3 && clean[1] == ':') { // \"/\" or \"C:\\\\\"\n    return fmt.Errorf(\"cache dir %q may not be a filesystem root\", clean)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never point a cache dir at / or a drive root — Hugo may prune cache dirs and refuses roots as a safety guard","Always include at least one subdirectory component under the placeholder","Double-check env-var expansion (an unset var can collapse a path to /)"],"tags":["hugo","filecache","config","safety","filesystem"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}