gofiber/fiber · error
limiter: failed to unmarshal key
Error message
limiter: failed to unmarshal key %q: %w
What it means
After a successful storage.GetWithContext, the raw bytes are handed to item.UnmarshalMsg (msgp-generated). If the bytes are not a valid msgpack-encoded item, this error fires. The acquired *item is released back to the pool before returning, so the leak is bounded to the bytes themselves.
Solutions
- Flush the affected limiter keys (or the whole storage namespace) so stale, differently-encoded values are cleared: redis-cli KEYS 'limiter:*' | xargs redis-cli DEL.
- Re-run go generate for the limiter package (msgp) and confirm manager_msgp.go is committed and matches the current item struct.
- Use a distinct key prefix per app/build so a new schema version cannot read an old version's values.
- If the corruption is from a shared namespace, set a unique StorageKeyPrefix in limiter.Config.
- Roll back to the previous build or migrate storage atomically with the code change.
Example fix
// before: shared prefix causes collision
limiter.New(limiter.Config{Storage: redisStore})
// after: namespace per build, flush on deploy
limiter.New(limiter.Config{Storage: redisStore, StorageKeyPrefix: "v2:limiter:"}) Defensive patterns
Strategy: validation
Validate before calling
// On deploy, verify no stale values collide with the new schema. // (infra step) redis-cli --scan --pattern 'limiter:*' | head; flush if schema changed.
Try / catch
// Treat unmarshal failures as a poisoned key: delete and continue.
if errors.Is(err, msgp.ErrShortBytes) { // or match the wrapped prefix
_ = storage.Del(key)
} Prevention
- Version the limiter key prefix per build (StorageKeyPrefix in limiter.Config) so schema changes cannot read old values.
- Re-run go generate ./middleware/limiter whenever the item struct changes.
- Never share the limiter's Redis key namespace with other middleware.
- Flush the limiter namespace on schema-affecting deploys.
When it happens
Trigger: Stored value for the limiter key was written by a different schema version (struct field reordered/renamed after msgp regeneration without clearing storage), the key namespace is shared with another fiber.Storage consumer that wrote arbitrary bytes, manual storage inspection/repopulation with wrong format, or storage corruption (truncated Redis value after a crash).
Common situations: Deploying a new fiber version where the internal `item` struct's msgp shape changed without flushing Redis; co-locating limiter keys in the same Redis DB as session keys with a colliding prefix; a Redis RDB/AOF restore from a backup made by a different app build.
Related errors
- cache: failed to unmarshal key
- failed to marshal response
- failed to unmarshal response
- fiber: failed to encode shared state
- limiter: failed to get key
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/608ab1575fc14dd0.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/limiter/manager.go:76
func (m *manager) release(e *item) {
e.prevHits = 0
e.currHits = 0
e.exp = 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("limiter: failed to get key %q from storage: %w", m.logKey(key), err)
}
if raw != nil {
it := m.acquire()
if _, err := it.UnmarshalMsg(raw); err != nil {
m.release(it)
return nil, fmt.Errorf("limiter: failed to unmarshal key %q: %w", m.logKey(key), err)
}
return it, nil
}
return m.acquire(), nil
}
value := m.memory.Get(key)
if value == nil {
return m.acquire(), nil
}
it, ok := value.(*item)
if !ok {
return nil, fmt.Errorf("limiter: unexpected entry type %T for key %q", value, m.logKey(key))
}
return it, nil
}View on GitHub (pinned to a105acad6c)