gofiber/fiber · warning
cache: failed to delete stale vary manifest
Error message
cache: failed to delete stale vary manifest %q: %w
What it means
Returned from the response path when, after purging an uncacheable entry (private/no-cache/Vary:*), the cache tries to also delete the associated Vary manifest and manager.del fails. The Vary manifest maps the base key to its vary-axis keys; leaving it stale would cause future requests to compute keys against an obsolete vary set, so the failure is surfaced.
Solutions
- Diagnose the wrapped delete error against the storage backend.
- Ensure the manifest key namespace is exclusive to the cache (no other writer uses the same prefix).
- If vary churn is high, audit upstream Vary usage to reduce axis count.
- Right-size storage pool and add reconnect/backoff.
- Reproduce with vary logging enabled to correlate manifest keys.
Example fix
// before: storage delete occasionally times out under load
// after: bound the storage client and add retries at the client level
cfg := cache.Config{Storage: storageWithRetries, DisableVaryHeaders: false} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the cache manifest key namespace is exclusive and deletes work.
func probeManifestDelete(s fiber.Storage, ns string) error {
k := ns + ":vary:probe"
if err := s.Set(k, []byte("{}"), time.Second); err != nil { return err }
return s.Delete(k)
} Try / catch
app.Use(func(c fiber.Ctx) error {
err := c.Next()
if err != nil && isCacheManifestDeleteErr(err) {
// manifest cleanup failed; future vary-key computation may be stale until next purge
return nil
}
return err
}) Prevention
- Reserve a dedicated key prefix for the cache (no foreign writers).
- Keep vary axis count low to reduce manifest churn.
- Add storage delete monitoring specific to the cache namespace.
- Reproduce with vary logging enabled to correlate manifest keys.
When it happens
Trigger: cfg.DisableVaryHeaders is false and the response path determined hasVaryManifest is true (a manifest was previously stored for this base key); the storage Delete for the manifest key fails. The masked manifest key is included for correlation.
Common situations: Storage backend transient failure during a vary-axis change; multi-instance deployment racing on the same base key; manifest key namespace clash; storage under pressure during vary-heavy traffic (e.g. content negotiation).
Related errors
- cache: failed to delete cached response for key
- cache: failed to delete private response for key
- cache: failed to delete expired key
- cache: failed to delete key
- cache: failed to delete key
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/f31003201f50bb59.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/cache/cache.go:633
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 nil
}
shouldStoreVaryManifest := !cfg.DisableVaryHeaders && len(varyNames) > 0
if !cfg.DisableVaryHeaders && len(varyNames) > 0 {
if key == baseKey {
key += buildVaryKey(varyNames, &c.Request().Header, canonical)
}
} else 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)
}
}
View on GitHub (pinned to a105acad6c)