{"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":null,"severity":"warning","filePath":"middleware/cache/cache.go","lineNumber":400,"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":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/cache/cache.go#L382-L418","documentation":"Fires when a cached entry is found to be private (entry.private flag set, or Cache-Control: private in stored headers) and the purge via deleteKey failed. Private responses must never be served to other clients, so cache attempts to delete on detection; failure returns this error and the request does not serve the stale private body.","triggerScenarios":"A response previously stored with Cache-Control: private (or marked private via StoreResponseHeaders) is later read; deleteKey is called to purge it and manager.del returns an error. Reproducible by storing a private response then breaking Delete on the storage.","commonSituations":"Upstream starts sending Cache-Control: private on a route that was previously shareable, turning existing entries private; remote storage briefly unavailable exactly when the private purge runs; misconfigured shared cache storing authorized responses.","solutions":["Don't cache private responses in a shared cache: ensure upstream omits 'private' or set cfg to exclude authorized responses (Fiber already guards hasAuthorization + non-shareable).","Diagnose and fix the storage Delete failure (the wrapped %w carries the driver error).","If using an in-memory cache (cfg.Storage == nil) this is effectively unreachable — switching to memory storage sidesteps remote Delete failures.","Flush storage to remove the offending private entries, then reseed under corrected cache-control policy."],"exampleFix":"// before: shared cache stored a private response that can't be purged\ncfg := cache.Config{Storage: sharedRedis}\n\n// after: stop caching private/authorized responses + fix storage\ncfg := cache.Config{\n  Storage: robustStorage,\n  Next: func(c fiber.Ctx) bool {\n    // skip caching when the response will be private\n    return len(c.Request().Header.Peek(fiber.HeaderAuthorization)) > 0\n  },\n}","handlingStrategy":"validation","validationCode":"// Prevent private responses from entering the cache in the first place.\ncfg := cache.Config{\n  Next: func(c fiber.Ctx) bool {\n    // Skip caching for requests that will yield private responses.\n    return len(c.Request().Header.Peek(fiber.HeaderAuthorization)) > 0\n  },\n}","typeGuard":"null","tryCatchPattern":"app.Use(func(c fiber.Ctx) error {\n    err := c.Next()\n    if err != nil && strings.Contains(err.Error(), \"failed to delete private response\") {\n        log.Warnf(\"private purge failed; entry remains in storage: %v\", err)\n        return nil\n    }\n    return err\n})","preventionTips":["Don't cache authorized/private responses in a shared cache.","Use cfg.Next to bypass caching for known-private routes.","Ensure upstream omits 'Cache-Control: private' for shareable content.","Flush storage after policy changes that affect private marking."],"tags":["cache","storage","private","delete","cache-control"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}