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
- 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).
- Confirm no other writer is producing keys under the same prefix used by the cache middleware; give the cache its own exclusive key namespace.
- 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.
- Regenerate msgp code with `make generate` after any change to the item struct so encoder/decoder stay in lockstep.
- 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
- Flush or re-namespace the cache (bump CacheModifier prefix) whenever the item struct changes.
- Give the cache its own exclusive key prefix in shared storage.
- Regenerate msgp with `make generate` after any item-struct change.
- Never manually SET keys under the cache namespace from other services.
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
- cache: failed to marshal key %q: %w
- cache: failed to get key %q from storage: %w
- cache: unexpected entry type %T for key %q
- cache: failed to get raw key %q from storage: %w
- cache: unexpected raw entry type %T for key %q
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/d744646cdf521b68.json.
Report an issue: GitHub.