gofiber/fiber · error
cache: failed to unmarshal key
Error message
cache: failed to unmarshal key %q: %w
What it means
Returned when bytes fetched from external Storage cannot be decoded back into an item via msgp UnmarshalMsg. The data exists in storage but is not a valid msgpack-encoded cache item, signaling either corruption, a schema/version mismatch, or foreign data written under the same key namespace.
Solutions
- Use a unique key prefix/namespace per app and per Fiber major version so cached bytes are never shared across incompatible schemas.
- Flush the affected Storage namespace after upgrading the cache middleware (the version mismatch self-heals as old entries expire/are overwritten).
- Verify no other writer is putting arbitrary bytes under keys your cache middleware owns.
- Confirm the msgp-generated code (manager_msgp.go) matches the item struct in the running binary — rebuild after schema changes.
Example fix
// before: unmarshal failure surfaces as a hard error
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)
}
// after: treat as corrupt entry — delete it and miss
if _, err := it.UnmarshalMsg(raw); err != nil {
m.release(it)
_ = m.storage.DeleteWithContext(ctx, key) // best-effort purge of stale/corrupt entry
return nil, errCacheMiss
} Defensive patterns
Strategy: type-guard
Validate before calling
// Use an isolated key namespace per app + Fiber major version so stale,
// differently-encoded entries can never be read by this code path.
const cacheKeyPrefix = "appA:fiberV3:"
func cacheKey(parts ...string) string {
return cacheKeyPrefix + strings.Join(parts, ":")
} Type guard
// Guard the decoded value is a plausible msgp item before returning it.
func looksLikeItem(raw []byte) bool {
// msgp array prefix for our item: a msgpack array header followed by expected shape.
// Cheap structural check; full validation happens in UnmarshalMsg.
return len(raw) > 0 && raw[0] == 0x9f || (raw[0]&0xf0 == 0x90) // fixarray family
} Try / catch
if _, err := it.UnmarshalMsg(raw); err != nil {
m.release(it)
// corrupt/incompatible entry — purge and miss rather than error
_ = m.storage.DeleteWithContext(ctx, key)
log.Warn("purged unreadable cache entry:", key, err)
return nil, errCacheMiss
} Prevention
- Namespace cache keys per app and per Fiber version.
- Flush the cache namespace after upgrades that change the item schema.
- Regenerate manager_msgp.go (make generate) whenever the item struct changes.
When it happens
Trigger: Cache lookup hits a key whose stored bytes fail it.UnmarshalMsg: another process/version wrote a different msgp schema under the same key prefix; storage corruption (truncated write, partial flush); key-namespace collision with another Fiber app sharing the same Redis DB without key isolation; msgp-generated code regenerated with different field limits after entries were written.
Common situations: Upgrading Fiber/cache versions where the item struct changed shape; two apps pointed at the same Redis DB with overlapping cache keys; storage engine crash mid-write leaving partial bytes; using a key prefix that collides with non-cache data.
Related errors
- cache: failed to marshal key
- cache: failed to delete key
- cache: failed to delete raw key
- cache: failed to get key
- cache: failed to get raw key
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/d744646cdf521b68.
Report an issue: GitHub.
Appendix: 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 a105acad6c)