{"id":"da9179e14f929dcc","repo":"gofiber/fiber","slug":"cache-failed-to-delete-raw-key-q-after-store-err","errorCode":null,"errorMessage":"cache: failed to delete raw key %q after store error: %w","messagePattern":"cache: failed to delete raw key %q after store error: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/cache/cache.go","lineNumber":853,"sourceCode":"\t\t\tspaceReserved = false // Clear flag to prevent defer from unreserving\n\t\t\tmux.Unlock()\n\t\t}\n\n\t\tcleanupOnStoreError := func(ctx context.Context, releaseEntry, rawStored bool) error {\n\t\t\tvar cleanupErr error\n\t\t\tif cfg.MaxBytes > 0 {\n\t\t\t\tmux.Lock()\n\t\t\t\t_, size := heap.remove(heapIdx)\n\t\t\t\tstoredBytes -= size\n\t\t\t\tmux.Unlock()\n\t\t\t}\n\t\t\tif releaseEntry {\n\t\t\t\tmanager.release(e)\n\t\t\t}\n\t\t\tif rawStored {\n\t\t\t\trawKey := key + \"_body\"\n\t\t\t\tif err := manager.del(ctx, rawKey); err != nil {\n\t\t\t\t\tcleanupErr = errors.Join(cleanupErr, fmt.Errorf(\"cache: failed to delete raw key %q after store error: %w\", maskKey(rawKey), err))\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn cleanupErr\n\t\t}\n\n\t\t// For external Storage we store raw body separated\n\t\tif cfg.Storage != nil {\n\t\t\tif err := manager.setRaw(reqCtx, key+\"_body\", e.body, storageExpiration); err != nil {\n\t\t\t\tif cleanupErr := cleanupOnStoreError(reqCtx, true, false); cleanupErr != nil {\n\t\t\t\t\terr = errors.Join(err, cleanupErr)\n\t\t\t\t}\n\t\t\t\treturn err\n\t\t\t}\n\t\t\t// avoid body msgp encoding\n\t\t\te.body = nil\n\t\t\tif err := manager.set(reqCtx, key, e, storageExpiration); err != nil {\n\t\t\t\tif cleanupErr := cleanupOnStoreError(reqCtx, false, true); cleanupErr != nil {\n\t\t\t\t\terr = errors.Join(err, cleanupErr)","sourceCodeStart":835,"sourceCodeEnd":871,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/cache/cache.go#L835-L871","documentation":"Raised by cleanupOnStoreError during the store path: an entry was being written, manager.setRaw for the '_body' raw key (or the main set) succeeded but the subsequent set failed, so cleanup tries to manager.del the raw '_body' key it just stored — and that delete also failed. The returned error joins the original store error with this cleanup error so neither is hidden.","triggerScenarios":"cfg.Storage != nil (external storage); setRaw of key+'_body' succeeded but manager.set(key, e) failed; the compensating manager.del of key+'_body' also failed. Reproducible by failing both set and del on the storage driver while caching a response body.","commonSituations":"Storage backend degrades mid-write (disk fills between setRaw and set); TLS connection reset means the follow-up del also fails; Redis failover window; an entry slightly over a quota where setRaw fit but set (msgp-encoded item) didn't, then del also broke.","solutions":["Stabilize the storage backend (capacity, connectivity, ACLs) — both writes and deletes are unreliable.","Out-of-band, flush orphaned '<key>_body' raw entries that the failed cleanup left behind.","Reduce per-entry size (cap response bodies via cfg.MaxBytes) to avoid partial-store situations.","If persistent, switch temporarily to in-memory cache (cfg.Storage == nil) which has no separate raw key."],"exampleFix":"// before: external storage partially stores then fails cleanup\ncfg := cache.Config{Storage: unstableStorage}\n\n// after: healthy storage + body size cap\ncfg := cache.Config{\n  Storage:    stableStorage,\n  MaxBytes:   1 << 20, // cap per-entry / total bytes\n  Expiration: 5 * time.Minute,\n}","handlingStrategy":"try-catch","validationCode":"func pingStorageSetDelete(s fiber.Storage) error {\n    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n    defer cancel()\n    k := []byte(\"__ping_body__\")\n    if err := s.Set(ctx, string(k), []byte(\"x\"), 5*time.Second); err != nil {\n        return err\n    }\n    return s.Delete(ctx, string(k))\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 raw key\") {\n        log.Errorf(\"cache store + cleanup failed: %v\", err)\n        return c.Status(fiber.StatusServiceUnavailable).SendString(\"cache unavailable\")\n    }\n    return err\n})","preventionTips":["Cap response body size with cfg.MaxBytes to avoid partial-store situations.","Keep storage capacity healthy so set and del both succeed.","Out-of-band, sweep orphaned '<key>_body' raw entries left by failed cleanups.","Temporarily use in-memory cache (cfg.Storage == nil) if the backend is unreliable."],"tags":["cache","storage","cleanup","raw-key","errors-join","write-failure"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}