{"record":{"id":"bc71beb012a2e49f","repo":"gofr-dev/gofr","slug":"requestspersecond-must-be-positive","errorCode":null,"errorMessage":"requestsPerSecond must be positive","messagePattern":"requestsPerSecond must be positive","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/http/middleware/rate_limiter.go","lineNumber":17,"sourceCode":"package middleware\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\n\tgofrHttp \"gofr.dev/pkg/gofr/http\"\n)\n\nvar (\n\t// errInvalidRequestsPerSecond is returned when RequestsPerSecond is not positive.\n\terrInvalidRequestsPerSecond = errors.New(\"requestsPerSecond must be positive\")\n\n\t// errInvalidBurst is returned when Burst is not positive.\n\terrInvalidBurst = errors.New(\"burst must be positive\")\n)\n\n// RateLimiterConfig holds configuration for rate limiting.\n//\n// Note: The default implementation uses in-memory token buckets and is suitable\n// for single-pod deployments. In multi-pod deployments, each pod will enforce\n// limits independently. For distributed rate limiting across multiple pods,\n// a Redis-backed store can be implemented in a future update.\n//\n// Security: When using PerIP=true, only enable TrustedProxies if your application\n// is behind a trusted reverse proxy (nginx, ALB, etc.) that sets X-Forwarded-For.\n// Without trusted proxies, clients can spoof IP addresses to bypass rate limits.\n//\n// Cleanup: The rate limiter starts a background goroutine that runs for the\n// application lifetime. This is acceptable for long-running servers but consider","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/http/middleware/rate_limiter.go#L1-L35","documentation":"errInvalidRequestsPerSecond is returned by RateLimiterConfig.Validate when RequestsPerSecond is zero or negative. The token-bucket rate limiter cannot function without a positive refill rate, so configuration is rejected up front.","triggerScenarios":"Constructing a RateLimiterConfig with RequestsPerSecond: 0, a negative value, or leaving it as the zero value in a struct literal that doesn't set it.","commonSituations":"Forgetting to set RequestsPerSecond because Go zero-values it; computing the rate from a config/env value that parses to 0; unit changes (per-minute vs per-second) yielding sub-1 values.","solutions":["Set RequestsPerSecond to a positive float (e.g. 10) in the RateLimiterConfig","If loading from config/env, validate the parsed value is > 0 before building the middleware","Provide a sensible default (e.g. 100) when the config value is missing"],"exampleFix":"// before\ncfg := middleware.RateLimiterConfig{}\n// after\ncfg := middleware.RateLimiterConfig{RequestsPerSecond: 100, Burst: 200}","handlingStrategy":"validation","validationCode":"if cfg.RequestsPerSecond <= 0 { return fmt.Errorf(\"RequestsPerSecond must be > 0, got %v\", cfg.RequestsPerSecond) }","typeGuard":"func validRateConfig(c RateLimiterConfig) bool { return c.RequestsPerSecond > 0 && c.Burst > 0 }","tryCatchPattern":null,"preventionTips":["Never rely on Go zero values for rate limit configs; set explicit defaults","Validate parsed env/config values before constructing middleware","Document required fields in your config struct"],"tags":["rate-limiting","configuration","middleware"],"backgroundTag":"invalid-rate-limiter-config","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}