{"record":{"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/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/cache/filecache/filecache_config.go#L265-L301","documentation":"DecodeConfig rejects a cache directory that resolves to a filesystem root (filecache_config.go:282-283), detected when stripping the volume name leaves a single character (e.g. / or C:\\). This is a safety guard because cache pruning deletes files, and operating on root would be catastrophic.","triggerScenarios":"Configuring cacheDir or a cache dir to resolve to / (Unix) or a drive root (Windows), e.g. cacheDir = \"/\".","commonSituations":"Empty or accidentally-rooted cacheDir; misconfigured placeholder resolution that lands on root; config migration errors.","solutions":["Point cacheDir to a subdirectory such as /home/user/.cache/hugo, never /","Verify the resolved path has at least one path component beyond root","Check that cacheDir config is not accidentally set to / or empty"],"exampleFix":"# before\ncacheDir = \"/\"\n# after\ncacheDir = \"/var/cache/hugo\"","handlingStrategy":"validation","validationCode":"// Reject root paths before they reach the config decoder.\nfunc isRootPath(dir string) bool {\n    withoutVol := strings.TrimPrefix(dir, filepath.VolumeName(dir))\n    return len(withoutVol) <= 1\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never set cacheDir to / or a bare drive root","Always include at least one subdirectory component in cache paths","Review config after migrations that might reset cacheDir"],"tags":["cache","filecache","config","safety","paths","hugo"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}