gofiber/fiber · warning

cache: failed to delete private response for key %q: %w

Error message

cache: failed to delete private response for key %q: %w

What it means

Fires when a cached entry is found to be private (entry.private flag set, or Cache-Control: private in stored headers) and the purge via deleteKey failed. Private responses must never be served to other clients, so cache attempts to delete on detection; failure returns this error and the request does not serve the stale private body.

Source

Thrown at middleware/cache/cache.go:400

				unlock()
				if err := deleteKey(reqCtx, key); err != nil {
					if e != nil {
						manager.release(e)
					}
					return fmt.Errorf("cache: failed to delete expired key %q: %w", maskKey(key), err)
				}
				relock()
				idx := e.heapidx
				manager.release(e)
				removeHeapEntry(key, idx)
				e = nil
			case entryHasPrivate:
				unlock()
				if err := deleteKey(reqCtx, key); err != nil {
					if e != nil {
						manager.release(e)
					}
					return fmt.Errorf("cache: failed to delete private response for key %q: %w", maskKey(key), err)
				}
				relock()
				removeHeapEntry(key, e.heapidx)
				if cfg.Storage != nil && e != nil {
					manager.release(e)
				}
				e = nil
				unlock()
				c.Set(cfg.CacheHeader, cacheUnreachable)
				if reqDirectives.onlyIfCached {
					return c.SendStatus(fiber.StatusGatewayTimeout)
				}
				return c.Next()
			case entryHasExpiration && !requestNoCache:
				servedStale = entryExpired
				if hasAuthorization && !e.shareable {
					if cfg.Storage != nil {
						manager.release(e)

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Don't cache private responses in a shared cache: ensure upstream omits 'private' or set cfg to exclude authorized responses (Fiber already guards hasAuthorization + non-shareable).
  2. Diagnose and fix the storage Delete failure (the wrapped %w carries the driver error).
  3. If using an in-memory cache (cfg.Storage == nil) this is effectively unreachable — switching to memory storage sidesteps remote Delete failures.
  4. Flush storage to remove the offending private entries, then reseed under corrected cache-control policy.

Example fix

// before: shared cache stored a private response that can't be purged
cfg := cache.Config{Storage: sharedRedis}

// after: stop caching private/authorized responses + fix storage
cfg := cache.Config{
  Storage: robustStorage,
  Next: func(c fiber.Ctx) bool {
    // skip caching when the response will be private
    return len(c.Request().Header.Peek(fiber.HeaderAuthorization)) > 0
  },
}
Defensive patterns

Strategy: validation

Validate before calling

// Prevent private responses from entering the cache in the first place.
cfg := cache.Config{
  Next: func(c fiber.Ctx) bool {
    // Skip caching for requests that will yield private responses.
    return len(c.Request().Header.Peek(fiber.HeaderAuthorization)) > 0
  },
}

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 private response") {
        log.Warnf("private purge failed; entry remains in storage: %v", err)
        return nil
    }
    return err
})

Prevention

When it happens

Trigger: A response previously stored with Cache-Control: private (or marked private via StoreResponseHeaders) is later read; deleteKey is called to purge it and manager.del returns an error. Reproducible by storing a private response then breaking Delete on the storage.

Common situations: Upstream starts sending Cache-Control: private on a route that was previously shareable, turning existing entries private; remote storage briefly unavailable exactly when the private purge runs; misconfigured shared cache storing authorized responses.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/c161b3e7f6b9aecb.json. Report an issue: GitHub.