{"record":{"id":"182b8e4d161b9ad9","repo":"gofiber/fiber","slug":"limiter-failed-to-store-key-q-w","errorCode":null,"errorMessage":"limiter: failed to store key %q: %w","messagePattern":"limiter: failed to store key %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/limiter/manager.go","lineNumber":106,"sourceCode":"\tit, ok := value.(*item)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"limiter: unexpected entry type %T for key %q\", value, m.logKey(key))\n\t}\n\n\treturn it, nil\n}\n\n// set data to storage or memory\nfunc (m *manager) set(ctx context.Context, key string, it *item, exp time.Duration) error {\n\tif m.storage != nil {\n\t\traw, err := it.MarshalMsg(nil)\n\t\tif err != nil {\n\t\t\tm.release(it)\n\t\t\treturn fmt.Errorf(\"limiter: failed to marshal key %q: %w\", m.logKey(key), err)\n\t\t}\n\t\tif err := m.storage.SetWithContext(ctx, key, raw, exp); err != nil {\n\t\t\tm.release(it)\n\t\t\treturn fmt.Errorf(\"limiter: failed to store key %q: %w\", m.logKey(key), err)\n\t\t}\n\t\tm.release(it)\n\t\treturn nil\n\t}\n\n\tm.memory.Set(key, it, exp)\n\treturn nil\n}\n\nfunc (m *manager) logKey(key string) string {\n\tif m.shouldRedactKeys {\n\t\treturn redactedKey\n\t}\n\treturn key\n}\n","sourceCodeStart":88,"sourceCodeEnd":122,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/limiter/manager.go#L88-L122","documentation":"The companion write error to error 180: storage.SetWithContext failed when persisting the updated hit count and expiry. The *item is released back to the pool on failure. The wrapped storage error is preserved for diagnosis.","triggerScenarios":"Redis OOM (maxmemory exceeded with noeviction), MySQL deadlocks or lock-wait timeout, storage disk full (SQLite), connection pool exhausted, context cancelled mid-write, ACL/permission denied on the storage namespace.","commonSituations":"Rate-limiter writes are write-heavy (one Set per request that hits the limiter); a Redis maxmemory policy of noeviction will start rejecting writes once the limit is hit; storage backend restarted mid-request; network partition between app and storage.","solutions":["Unwrap the error to find the storage-specific cause (e.g. OOM, LOCK_WAIT_TIMEOUT).","For Redis: raise maxmemory or switch to an eviction policy that suits limiter semantics (allkeys-lru), and confirm maxclients is above your peak concurrency.","Confirm the storage connection pool size >= expected concurrent limiter writes.","Shorten limiter Expiration to reduce storage churn if keys accumulate.","If context cancellation is the cause, ensure the request lifetime exceeds storage write latency."],"exampleFix":"// before: default redis with noeviction, writes fail under load\nredis.NewRaw(redis.Config{URL: redisURL})\n\n// after: sized maxmemory and eviction\nredis.NewRaw(redis.Config{URL: redisURL}) // plus redis.conf: maxmemory 256mb, maxmemory-policy allkeys-lru","handlingStrategy":"retry","validationCode":"// Pre-flight: confirm storage write capacity.\nif err := store.Set(\"healthcheck\", []byte(\"ok\"), time.Minute); err != nil {\n  return fmt.Errorf(\"storage not writable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"// On write failure, degrade gracefully (e.g. fail-open with a log) if business permits.\nif errors.Is(err, storage.ErrWrite) {\n  log.Printf(\"limiter write failed, failing open: %v\", err)\n}","preventionTips":["Choose a Redis maxmemory policy that admits limiter writes (e.g. allkeys-lru, not noeviction).","Size maxclients and the connection pool above peak concurrency.","Keep limiter Expiration short enough that the working set fits in memory.","Monitor storage write-error rate as a leading indicator."],"tags":["limiter","storage","redis","rate-limiting","write"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}