{"id":"c30b49cd7bdf0d64","repo":"gohugoio/hugo","slug":"failed-to-prune-cache-q-w","errorCode":null,"errorMessage":"failed to prune cache %q: %w","messagePattern":"failed to prune cache %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cache/filecache/filecache_pruner.go","lineNumber":43,"sourceCode":"\t\"github.com/spf13/afero\"\n)\n\n// Prune removes expired and unused items from this cache.\n// The last one requires a full build so the cache usage can be tracked.\n// Note that we operate directly on the filesystem here, so this is not\n// thread safe.\nfunc (c Caches) Prune() (int, error) {\n\tcounter := 0\n\tfor k, cache := range c {\n\t\tcount, err := cache.Prune(false)\n\n\t\tcounter += count\n\n\t\tif err != nil {\n\t\t\tif herrors.IsNotExist(err) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn counter, fmt.Errorf(\"failed to prune cache %q: %w\", k, err)\n\t\t}\n\n\t}\n\n\treturn counter, nil\n}\n\n// Prune removes expired and unused items from this cache.\n// If force is set, everything will be removed not considering expiry time.\nfunc (c *Cache) Prune(force bool) (int, error) {\n\tif c.cfg.entryIsDir {\n\t\treturn c.pruneRootDirs(force)\n\t}\n\tif err := c.init(); err != nil {\n\t\treturn 0, err\n\t}\n\n\tcounter := 0","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/cache/filecache/filecache_pruner.go#L25-L61","documentation":"`Caches.Prune` iterates every configured file cache (getjson, getcsv, images, assets, modules, getresource) and removes expired or unused entries; it operates directly on the filesystem. If pruning one cache fails for any reason other than the directory not existing, the loop stops and wraps the failure with the cache's key so you know which cache was being cleaned.","triggerScenarios":"Running `hugo --gc` or `hugo server` with GC enabled: `cache.Prune(false)` on a specific cache returns a non-IsNotExist error — e.g. permission denied deleting an entry, an entry directory locked by another process, or filesystem I/O errors while walking/removing cache files.","commonSituations":"Cache directories created by a different user (root-built Docker layer, then non-root prune); antivirus or backup tools holding locks on cache files on Windows; NFS/network-mounted cache dirs with flaky delete semantics; two concurrent Hugo builds sharing one cache dir (Prune is documented as not thread safe).","solutions":["Check the cache name in the error and fix permissions on that subdirectory under your cache root (`chown -R` to the build user).","Stop concurrent Hugo processes sharing the same cache dir before running `--gc`.","If the cache is corrupted, delete the named cache subdirectory (or the whole cache root) manually and rebuild."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# Confirm cache subdirs are intact and writable before pruning:\nfind \"$HUGO_CACHEDIR\" -maxdepth 1 -type d ! -writable","typeGuard":null,"tryCatchPattern":"if err := prune(); err != nil {\n    // %q names the specific cache that failed — often safe to delete it wholesale\n    log.Printf(\"prune failed: %v — removing that cache dir manually and continuing\", err)\n}","preventionTips":["Run `hugo --gc` from the same user/permissions that created the cache","If a specific cache repeatedly fails to prune, delete its directory and let Hugo recreate it","Avoid pruning while another Hugo build is writing to the same cache","Keep the cache on a local filesystem, not flaky network mounts"],"tags":["hugo","filecache","gc","permissions"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}