gofiber/fiber · warning
cache: failed to delete stale vary manifest %q: %w
Error message
cache: failed to delete stale vary manifest %q: %w
What it means
On the same response path as 134, after marking the response uncacheable: if Vary header tracking is enabled and a stale vary manifest previously existed for this base key, Fiber calls manager.del(manifestKey) to remove it; failure returns this error. The manifest is the per-base-key index of Vary-driven sub-partitions, so leaving it stale can cause future lookups to mis-partition.
Source
Thrown at middleware/cache/cache.go:551
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)
}
} 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 9a4c7e57fe)
Solutions
- Diagnose the wrapped storage Delete error and stabilize the backend.
- If Vary partitioning isn't needed, set DisableVaryHeaders: true to skip manifest bookkeeping entirely.
- Flush stale manifests by clearing the storage namespace after policy changes.
- Reduce concurrent races by narrowing cfg.Methods / cfg.Next so only stable cacheable routes participate.
Example fix
// before: vary manifests accumulate and Delete fails
cfg := cache.Config{Storage: flakyStorage}
// after: disable vary bookkeeping where not needed + healthy storage
cfg := cache.Config{
Storage: robustStorage,
DisableVaryHeaders: true,
} Defensive patterns
Strategy: validation
Validate before calling
// If vary partitioning isn't needed, disable it to avoid manifest maintenance.
cfg := cache.Config{DisableVaryHeaders: true} 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 stale vary manifest") {
log.Warnf("stale vary manifest purge failed: %v", err)
return nil
}
return err
}) Prevention
- Set DisableVaryHeaders: true when Vary partitioning isn't required.
- Keep Vary header usage consistent across responses for the same route.
- Flush cache storage after changing Vary behavior.
- Stabilize storage Delete reliability to avoid manifest orphans.
When it happens
Trigger: DisableVaryHeaders is false, hasVaryManifest is true, response is uncacheable (private/no-cache/Vary:*), and manager.del of the manifestKey fails. Reproducible by storing a varied response, then sending an uncacheable response for the same base key while breaking storage Delete.
Common situations: Vary-aware caching where the upstream changes a route to private/no-cache while old vary manifests linger; remote storage Delete hiccups during the transition; concurrent requests racing to mutate the same manifestKey.
Related errors
- cache: failed to delete expired key %q: %w
- cache: failed to delete private response for key %q: %w
- cache: failed to delete cached response for key %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/f31003201f50bb59.json.
Report an issue: GitHub.