{"record":{"id":"6de1f45b0a0e9feb","repo":"gofiber/fiber","slug":"cache-failed-to-delete-expired-key-q-w","errorCode":null,"errorMessage":"cache: failed to delete expired key %q: %w","messagePattern":"cache: failed to delete expired key %q: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"middleware/cache/cache.go","lineNumber":365,"sourceCode":"\t\t\thandleMinFresh(ts)\n\t\t}\n\n\t\tif e != nil && e.ttl == 0 && e.forceRevalidate {\n\t\t\trevalidate = true\n\t\t\toldHeapIdx = e.heapidx\n\t\t\tif cfg.Storage != nil {\n\t\t\t\tmanager.release(e)\n\t\t\t}\n\t\t\te = nil\n\t\t}\n\n\t\tif e != nil && e.ttl == 0 && e.exp != 0 && ts >= e.exp {\n\t\t\tunlock()\n\t\t\tif err := deleteKey(reqCtx, key); err != nil {\n\t\t\t\tif cfg.Storage != nil {\n\t\t\t\t\tmanager.release(e)\n\t\t\t\t}\n\t\t\t\treturn fmt.Errorf(\"cache: failed to delete expired key %q: %w\", maskKey(key), err)\n\t\t\t}\n\t\t\trelock()\n\t\t\tremoveHeapEntry(key, e.heapidx)\n\t\t\tif cfg.Storage != nil {\n\t\t\t\tmanager.release(e)\n\t\t\t}\n\t\t\te = nil\n\t\t\tunlock()\n\t\t\tc.Set(cfg.CacheHeader, cacheUnreachable)\n\t\t\tgoto continueRequest\n\t\t}\n\n\t\tif e != nil {\n\t\t\tentryHasPrivate := e != nil && e.private\n\t\t\tif !entryHasPrivate && cfg.StoreResponseHeaders && len(e.headers) > 0 {\n\t\t\t\tif cc, ok := lookupCachedHeader(e.headers, fiber.HeaderCacheControl); ok && hasDirective(utils.UnsafeString(cc), privateDirective) {\n\t\t\t\t\tentryHasPrivate = true\n\t\t\t\t}","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/cache/cache.go#L347-L383","documentation":"Returned from the request hot path (around cache.go:365) when an expired entry is detected and deleteKey fails to remove it from storage. This is the inline expired-entry cleanup: the entry's ttl==0, exp!=0, and ts>=exp mark it as expired; the cache attempts to delete it so future requests miss and re-fetch, but the storage delete errored. The masked key is logged to avoid leaking sensitive path content.","triggerScenarios":"cfg.Storage is set and the backend's Delete returns an error during inline expiration; storage backend temporarily unreachable; the request context (reqCtx) is canceled before the delete completes; multi-instance deployment where another node raced the same key.","commonSituations":"Redis restart during a traffic spike hitting expired keys; storage network blip; client disconnect cancels reqCtx; storage Delete latency spike under load.","solutions":["Inspect the wrapped delete error to find the backend cause.","Add health checks and reconnect logic to the storage client.","Ensure reqCtx is derived from the request lifecycle, not a longer-lived context.","For Redis, confirm maxmemory-policy and connection pool health.","If using in-memory only (Storage == nil), this path is unreachable because deleteKey short-circuits."],"exampleFix":"// before: shared storage with no delete timeout, occasional blips\ncfg := cache.Config{Storage: redisClient}\n\n// after: client with sane dial/read/write timeouts\nredisClient := redis.NewClient(&redis.Options{DialTimeout: 2*time.Second, ReadTimeout: 500*time.Millisecond})","handlingStrategy":"try-catch","validationCode":"// Confirm storage Delete works before relying on inline expiration.\nfunc probeDelete(s fiber.Storage) error {\n    if err := s.Set(\"probe:del\", []byte(\"v\"), time.Second); err != nil { return err }\n    return s.Delete(\"probe:del\")\n}","typeGuard":null,"tryCatchPattern":"app.Use(func(c fiber.Ctx) error {\n    err := c.Next()\n    if err != nil && isCacheDeleteErr(err) {\n        // treat a delete failure on expired key as non-fatal; expire on next pass\n        return nil\n    }\n    return err\n})","preventionTips":["Use a storage client with bounded timeouts and reconnect logic.","Ensure reqCtx derives from the request lifecycle, not a longer-lived context.","Monitor delete error rate as a leading indicator of storage trouble.","If Storage is nil (in-memory), this path is unreachable."],"tags":["cache","storage","expiration","delete","request-path"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}