gofiber/fiber · error

cache: insufficient space and no entries to evict

Error message

cache: insufficient space and no entries to evict

What it means

Returned inline (not a sentinel var) by the cache middleware's eviction loop when MaxBytes is set, a new response body is being cached, and after reserving space for it the eviction loop has drained the entire expiration heap and storedBytes still exceeds MaxBytes. This means no remaining cached entry can be evicted to make room, so the new entry cannot be stored. The error propagates out of the cache handler and surfaces as a 500 if not otherwise handled.

Source

Thrown at middleware/cache/cache.go:631

		if cfg.MaxBytes > 0 {
			mux.Lock()
			// Reserve space for the new entry first
			storedBytes += bodySize
			spaceReserved = true

			// Now evict entries until we're under the limit
			var keysToRemove []string
			var sizesToRemove []uint
			var candidates []evictionCandidate

			for storedBytes > cfg.MaxBytes {
				if heap.Len() == 0 {
					// Can't evict more, unreserve space and fail
					storedBytes -= bodySize
					// Set spaceReserved to false so the deferred cleanup does not unreserve again
					spaceReserved = false
					mux.Unlock()
					return errors.New("cache: insufficient space and no entries to evict")
				}
				next := heap.entries[0]
				keyToRemove, size := heap.removeFirst()
				keysToRemove = append(keysToRemove, keyToRemove)
				sizesToRemove = append(sizesToRemove, size)
				candidates = append(candidates, evictionCandidate{
					key:  keyToRemove,
					size: size,
					exp:  next.exp,
				})
				storedBytes -= size
			}
			mux.Unlock()

			// Perform deletions outside the lock
			if len(keysToRemove) > 0 {
				for i, keyToRemove := range keysToRemove {
					delErr := deleteKey(reqCtx, keyToRemove)

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Increase cache.Config.MaxBytes so it comfortably exceeds your largest cacheable response plus headroom.
  2. If the value is correct, reduce the size of responses being cached (compression, pagination) or lower CacheExpiration so entries expire and free space.
  3. Set MaxBytes to 0 to disable the byte budget entirely (only time-based expiration applies).
  4. Inspect the X-Cache response header to confirm which responses are failing to cache before tuning.

Example fix

// before
app.Use(cache.New(cache.Config{
  MaxBytes: 1024, // smaller than typical JSON responses
}))
// after
app.Use(cache.New(cache.Config{
  MaxBytes: 50 * 1024 * 1024, // 50 MB budget
}))
Defensive patterns

Strategy: validation

Validate before calling

// Validate MaxBytes vs expected response sizes at startup
if cfg.MaxBytes > 0 && cfg.MaxBytes < maxExpectedResponse {
    log.Printf("warning: cache MaxBytes (%d) smaller than largest cacheable response (%d)", cfg.MaxBytes, maxExpectedResponse)
}

Try / catch

// The cache middleware returns the error from the handler; wrap your routes
app.Use(cache.New(cfg))
app.Use(func(c fiber.Ctx) error {
    err := c.Next()
    if err != nil && strings.Contains(err.Error(), "insufficient space") {
        c.Set("X-Cache", "unreachable")
        return c.SendStatus(fiber.StatusInternalServerError)
    }
    return err
})

Prevention

When it happens

Trigger: Setting cache.Config.MaxBytes to a value smaller than a single cached response body that passes the per-entry bodySize check (line 592 only rejects bodies larger than MaxBytes up front; a body just under MaxBytes still triggers this when the heap is otherwise empty). It also occurs when concurrent cache writes exhaust the heap between reservation and eviction.

Common situations: Setting MaxBytes very low (e.g. 1KB) while serving responses near that size; misjudging units (bytes vs KB); running under memory pressure where the cache is already full of non-expired entries; test environments with artificially tiny caches.

Related errors


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