gofiber/fiber · error

cache: failed to unmarshal key %q: %w

Error message

cache: failed to unmarshal key %q: %w

What it means

Thrown at middleware/cache/manager.go:123 when storage.GetWithContext returned bytes but msgp's it.UnmarshalMsg(raw) failed to decode them back into the internal *item struct. The bytes are present but not a valid msgpack payload matching the cache's item schema. This is a data-integrity / version-drift signal, not a transient network error.

Source

Thrown at middleware/cache/manager.go:123

	e.heapidx = 0
	m.pool.Put(e)
}

// get data from storage or memory
func (m *manager) get(ctx context.Context, key string) (*item, error) {
	if m.storage != nil {
		raw, err := m.storage.GetWithContext(ctx, key)
		if err != nil {
			return nil, fmt.Errorf("cache: failed to get key %q from storage: %w", m.logKey(key), err)
		}
		if raw == nil {
			return nil, errCacheMiss
		}

		it := m.acquire()
		if _, err := it.UnmarshalMsg(raw); err != nil {
			m.release(it)
			return nil, fmt.Errorf("cache: failed to unmarshal key %q: %w", m.logKey(key), err)
		}

		return it, nil
	}

	if value := m.memory.Get(key); value != nil {
		it, ok := value.(*item)
		if !ok {
			return nil, fmt.Errorf("cache: unexpected entry type %T for key %q", value, m.logKey(key))
		}
		return it, nil
	}

	return nil, errCacheMiss
}

// get raw data from storage or memory
func (m *manager) getRaw(ctx context.Context, key string) ([]byte, error) {

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Flush or namespace-isolate the cache storage after upgrading fiber/cache versions so old msgp payloads cannot be read by new code (e.g. bump CacheModifier / key prefix, or run Reset on the storage).
  2. Confirm no other writer is producing keys under the same prefix used by the cache middleware; give the cache its own exclusive key namespace.
  3. If the wrapped msgp error mentions a specific field/limit, compare the item struct in middleware/cache/manager.go against the version that wrote the data.
  4. Regenerate msgp code with `make generate` after any change to the item struct so encoder/decoder stay in lockstep.
  5. Treat the corrupted entry as stale: delete the offending key and let the cache repopulate on the next request.

Example fix

// before: cache shares the default key namespace with other apps
app.Use(cache.New(cache.Config{ Storage: redis.New() }))

// after: versioned key prefix isolates schema generations; flush old on deploy
app.Use(cache.New(cache.Config{
    Storage:      redis.New(),
    CacheModifier: func(c fiber.Ctx) string {
        return "v2:" + c.Path() // bump to v3 on next schema change
    },
}))
Defensive patterns

Strategy: validation

Validate before calling

// At deploy, ensure the cache keyspace is isolated per schema generation.
store.Reset() // or bump the key prefix in CacheModifier
// Then validate a round-trip works:
item := newItemSample()
raw, _ := item.MarshalMsg(nil)
_ = store.SetWithContext(ctx, "probe:v2", raw, time.Minute)
back, err := store.GetWithContext(ctx, "probe:v2")
var it2 item
if _, err := it2.UnmarshalMsg(back); err != nil {
    log.Fatalf("cache schema mismatch: %v", err)
}

Try / catch

// Distinguish a corrupt/unmarshalable entry from a real failure.
raw, err := m.storage.GetWithContext(ctx, key)
if err == nil && raw != nil {
    var it item
    if _, uerr := it.UnmarshalMsg(raw); uerr != nil {
        log.Printf("deleting corrupt cache entry %q: %v", key, uerr)
        _ = m.storage.DeleteWithContext(ctx, key) // reclaim; let next request repopulate
        return nil, errCacheMiss
    }
}

Prevention

When it happens

Trigger: Deploying a new version of fiber/cache whose msgp-generated item layout differs from the entries already sitting in the shared storage (e.g. fields added/removed, limit tags changed); another service writing arbitrary bytes under a key prefix the cache middleware also reads; storage corruption (truncated value, partial write); manual tampering via redis-cli SET.

Common situations: Rolling deploy where old-format cache entries survive in Redis and are read by new-format code; two apps sharing one Redis keyspace with overlapping key prefixes; a migration that changed the item struct without flushing the cache; storage backend returning truncated reads under disk pressure.

Related errors


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