{"record":{"id":"c161b3e7f6b9aecb","repo":"gofiber/fiber","slug":"cache-failed-to-delete-private-response-for-key","errorCode":null,"errorMessage":"cache: failed to delete private response for key %q: %w","messagePattern":"cache: failed to delete private response for key %q: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"middleware/cache/cache.go","lineNumber":448,"sourceCode":"\t\t\t\tunlock()\n\t\t\t\tif err := deleteKey(reqCtx, key); err != nil {\n\t\t\t\t\tif e != nil {\n\t\t\t\t\t\tmanager.release(e)\n\t\t\t\t\t}\n\t\t\t\t\treturn fmt.Errorf(\"cache: failed to delete expired key %q: %w\", maskKey(key), err)\n\t\t\t\t}\n\t\t\t\trelock()\n\t\t\t\tidx := e.heapidx\n\t\t\t\tmanager.release(e)\n\t\t\t\tremoveHeapEntry(key, idx)\n\t\t\t\te = nil\n\t\t\tcase entryHasPrivate:\n\t\t\t\tunlock()\n\t\t\t\tif err := deleteKey(reqCtx, key); err != nil {\n\t\t\t\t\tif e != nil {\n\t\t\t\t\t\tmanager.release(e)\n\t\t\t\t\t}\n\t\t\t\t\treturn fmt.Errorf(\"cache: failed to delete private response for key %q: %w\", maskKey(key), err)\n\t\t\t\t}\n\t\t\t\trelock()\n\t\t\t\tremoveHeapEntry(key, e.heapidx)\n\t\t\t\tif cfg.Storage != nil && e != nil {\n\t\t\t\t\tmanager.release(e)\n\t\t\t\t}\n\t\t\t\te = nil\n\t\t\t\tunlock()\n\t\t\t\tc.Set(cfg.CacheHeader, cacheUnreachable)\n\t\t\t\tif reqDirectives.onlyIfCached {\n\t\t\t\t\treturn c.SendStatus(fiber.StatusGatewayTimeout)\n\t\t\t\t}\n\t\t\t\treturn c.Next()\n\t\t\tcase entryHasExpiration && !requestNoCache:\n\t\t\t\tservedStale = entryExpired\n\t\t\t\tif hasAuthorization && !e.shareable {\n\t\t\t\t\tif cfg.Storage != nil {\n\t\t\t\t\t\tmanager.release(e)","sourceCodeStart":430,"sourceCodeEnd":466,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/cache/cache.go#L430-L466","documentation":"Returned from the request hot path when a cached entry is found to be private (Authorization/Cache-Control: private triggered entryHasPrivate) and the subsequent deleteKey fails. Private responses must not be served from a shared cache, so Fiber attempts to purge the stored entry; a storage delete failure means the private entry could persist and leak, hence the explicit error.","triggerScenarios":"A response previously cached is later classified private (e.g. an Authorization header appeared on the request, or the response's Cache-Control: private was just observed), and the storage Delete for that key fails. The cache sets the CacheHeader to cacheUnreachable and, if only-if-cached was requested, returns 504.","commonSituations":"Mixed-content caching where some responses are public and others private under the same key shape; storage blip during the private purge; misconfigured Vary so private and public responses collide on a key; client sending Authorization on a previously-public cached resource.","solutions":["Ensure Vary headers (Authorization at minimum) are honored so private responses get distinct keys: do not set cfg.DisableVaryHeaders.","Diagnose the wrapped delete error against the storage backend.","Audit upstream Cache-Control: private usage to confirm caching is intentional.","Confirm storage connectivity and delete permissions.","Reproduce with logging that prints the (masked) key to correlate with Vary mismatch."],"exampleFix":"// before: vary disabled, private responses collide with public ones\ncfg := cache.Config{DisableVaryHeaders: true}\n\n// after: keep vary enabled so Authorization yields a distinct key\ncfg := cache.Config{CacheControl: true}","handlingStrategy":"validation","validationCode":"// Ensure Vary is honored so private responses do not collide with public ones.\nfunc validateCacheConfig(cfg cache.Config) error {\n    if cfg.DisableVaryHeaders {\n        // risky: private responses may share a key with public ones\n        return fmt.Errorf(\"DisableVaryHeaders must be false when caching authenticated responses\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"app.Use(func(c fiber.Ctx) error {\n    err := c.Next()\n    if err != nil && isCachePrivateDeleteErr(err) {\n        // do not serve the cached private response; fall through\n        return nil\n    }\n    return err\n})","preventionTips":["Do not set cfg.DisableVaryHeaders when authenticated responses may be cached.","Ensure upstream sends proper Cache-Control: private for authenticated content.","Audit Vary usage so private and public responses get distinct keys.","Monitor delete error rate and treat private-purge failures as a security signal."],"tags":["cache","storage","private","delete","vary","security"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}