gofiber/fiber · warning

cache: failed to restore heap index for key

Error message

cache: failed to restore heap index for key %q: %w

What it means

Returned by refreshHeapIndex when the entry WAS successfully re-read from storage but manager.set fails while writing back the restored heapidx. This is the second half of eviction rollback: read worked, write failed. The wrapped error is from the storage backend's Set operation (e.g. Redis SET failed, context canceled, TTL write rejected).

Solutions

  1. Check storage capacity and eviction policy: redis-cli INFO memory; if noeviction, raise maxmemory or pick an eviction policy.
  2. Inspect the wrapped Set error for backend-specific causes.
  3. Ensure the request context is not being canceled prematurely (long upstream handler holding the lock).
  4. Scale storage or shard the cache to reduce write pressure.
  5. Reproduce with the cache middleware's instrumentation enabled to correlate GET/SET timing.

Example fix

// before: redis with maxmemory-policy noeviction
CONFIG SET maxmemory-policy noeviction

// after
CONFIG SET maxmemory-policy allkeys-lru
// and/or raise maxmemory
Defensive patterns

Strategy: validation

Validate before calling

// Validate storage write capacity before enabling MaxBytes eviction.
func canWriteAtScale(s fiber.Storage, n int) error {
    for i := 0; i < n; i++ {
        if err := s.Set(fmt.Sprintf("probe:%d", i), []byte("x"), time.Minute); err != nil {
            return fmt.Errorf("storage write probe %d failed: %w", i, err)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: Backend accepts the GET but rejects the SET during eviction rollback: storage near capacity with eviction policy nosql-eviction-off, write blacklist, connection drop between GET and SET, or the request context expires between the two calls.

Common situations: Redis maxmemory-policy set to noeviction (writes fail when full); storage node failover between read and write; long TTL differences causing a SET to be rejected; network partition mid-request.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/a80c0a82968ca269. Report an issue: GitHub.

Appendix: source

Thrown at middleware/cache/cache.go:219

		_, size := heap.remove(heapIdx)
		storedBytes -= size
	}

	refreshHeapIndex := func(ctx context.Context, candidate evictionCandidate) error {
		entry, err := manager.get(ctx, candidate.key)
		if err != nil {
			if errors.Is(err, errCacheMiss) {
				return nil
			}
			return fmt.Errorf("cache: failed to reload key %q after eviction failure: %w", maskKey(candidate.key), err)
		}

		entry.heapidx = candidate.heapIdx

		remainingTTL := max(secondsToTime(entry.exp).Sub(cfg.now()), 0)

		if err := manager.set(ctx, candidate.key, entry, remainingTTL); err != nil {
			return fmt.Errorf("cache: failed to restore heap index for key %q: %w", maskKey(candidate.key), err)
		}

		return nil
	}

	// Return new handler
	return func(c fiber.Ctx) error {
		// Every field line, like the hash below: an empty first Authorization line
		// would otherwise read as anonymous. canonical is app config, fixed for the
		// life of the handler, so read it once.
		canonical := headerlookup.Canonical(c)

		hasAuthorization := false
		for _, v := range fieldname.Lines(&c.Request().Header, fiber.HeaderAuthorization, canonical) {
			if len(v) > 0 {
				hasAuthorization = true
				break
			}

View on GitHub (pinned to a105acad6c)