gofiber/fiber · warning
cache: failed to delete cached response for key %q: %w
Error message
cache: failed to delete cached response for key %q: %w
What it means
On the response-write path: an existing cached entry exists and the new response carries Cache-Control: private, no-cache, or Vary: *, all of which make it uncacheable. Fiber tries to delete the old entry to honor RFC 9111 and deleteKey failed. The response is still sent to the client (c.Set CacheHeader=cacheUnreachable) but the stale entry remains in storage.
Source
Thrown at middleware/cache/cache.go:538
hasPrivate := respCacheControl.hasPrivate
hasNoCache := respCacheControl.hasNoCache
varyNames, varyHasStar := parseVary(varyHeader)
// Respect server cache-control: no-store
if respCacheControl.hasNoStore {
c.Set(cfg.CacheHeader, cacheUnreachable)
return nil
}
// RFC 9111 requires responses with Vary: * to remain uncacheable even when
// response-driven Vary partitioning is otherwise disabled.
if hasPrivate || hasNoCache || varyHasStar {
if e != nil {
if err := deleteKey(reqCtx, key); err != nil {
if cfg.Storage != nil {
manager.release(e)
}
return fmt.Errorf("cache: failed to delete cached response for key %q: %w", maskKey(key), err)
}
mux.Lock()
removeHeapEntry(key, e.heapidx)
if cfg.Storage != nil {
manager.release(e)
}
e = nil
mux.Unlock()
}
if !cfg.DisableVaryHeaders && hasVaryManifest {
if err := manager.del(reqCtx, manifestKey); err != nil {
return fmt.Errorf("cache: failed to delete stale vary manifest %q: %w", maskKey(manifestKey), err)
}
}
c.Set(cfg.CacheHeader, cacheUnreachable)
return nilView on GitHub (pinned to 9a4c7e57fe)
Solutions
- Resolve the underlying storage Delete failure (see wrapped %w).
- Flush the storage so previously-cached entries that should no longer be cached are removed out of band.
- Align upstream cache-control so it doesn't oscillate between cacheable and private/no-cache for the same route.
- Consider cfg.Next to bypass caching for known-private routes, removing the delete-on-conflict path entirely.
Example fix
// before: storage Delete fails purging old entry on private response
cfg := cache.Config{Storage: flakyStorage}
// after: skip cache for private routes + robust storage
cfg := cache.Config{
Storage: robustStorage,
Next: func(c fiber.Ctx) bool {
return c.Path() == "/me" // known-private route
},
} Defensive patterns
Strategy: validation
Validate before calling
// Skip caching routes that frequently return private/no-cache.
cfg := cache.Config{
Next: func(c fiber.Ctx) bool {
return c.Path() == "/login" || c.Path() == "/account"
},
} Type guard
null
Try / catch
app.Use(func(c fiber.Ctx) error {
err := c.Next()
if err != nil && strings.Contains(err.Error(), "failed to delete cached response") {
log.Warnf("uncacheable-response purge failed: %v", err)
return nil
}
return err
}) Prevention
- Keep origin cache-control policy stable per route.
- Bypass caching for known-private routes via cfg.Next.
- Flush storage when origin cache-control semantics change.
- Diagnose wrapped storage Delete errors before they recur.
When it happens
Trigger: A cached entry exists for a key; the origin now returns 'Cache-Control: private' (or 'no-cache' / 'Vary: *') for that key; deleteKey is called and manager.del returns an error. Triggered by upstream cache-control policy changes coinciding with a storage Delete failure.
Common situations: Origin tightens its cache-control (login-gated content); two responses racing for the same key where one is private; storage backend transiently unavailable; switching storage drivers without flushing the old entries.
Related errors
- cache: failed to delete private response for key %q: %w
- cache: failed to delete expired key %q: %w
- cache: failed to delete stale vary manifest %q: %w
- cache: failed to delete key %q while evicting: %w
- cache: failed to reload key %q after eviction failure: %w
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/dcfd2e94b80aacf1.json.
Report an issue: GitHub.