{"record":{"id":"a4d88728971210ec","repo":"gofr-dev/gofr","slug":"requests-must-be-greater-than-0-per-configured-tim","errorCode":null,"errorMessage":"requests must be greater than 0 per configured time window","messagePattern":"requests must be greater than 0 per configured time window","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/service/rate_limiter_config.go","lineNumber":11,"sourceCode":"package service\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n)\n\nvar (\n\terrInvalidRequestRate     = errors.New(\"requests must be greater than 0 per configured time window\")\n\terrBurstLessThanRequests  = errors.New(\"burst must be greater than requests per window\")\n\terrInvalidRedisResultType = errors.New(\"unexpected Redis result type\")\n)\n\nconst (\n\tunknownServiceKey = \"unknown\"\n\tmethodHTTP        = \"http\"\n\tmethodHTTPS       = \"https\"\n)\n\n// RateLimiterConfig with custom keying support.\ntype RateLimiterConfig struct {\n\tRequests float64                    // Number of requests allowed\n\tWindow   time.Duration              // Time window (e.g., time.Minute, time.Hour)\n\tBurst    int                        // Maximum burst capacity (must be > 0)\n\tKeyFunc  func(*http.Request) string // Optional custom key extraction\n\tStore    RateLimiterStore\n}","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/service/rate_limiter_config.go#L1-L29","documentation":"errInvalidRequestRate (rate_limiter_config.go:11) is returned by RateLimiterConfig.Validate when Requests <= 0 — a rate limiter that allows zero requests per window is meaningless. Validate reports the error but still repairs the config by defaulting Requests to 60, so callers that ignore the return value get a silently defaulting limiter.","triggerScenarios":"Constructing RateLimiterConfig{Requests: 0} (or negative, or left as the zero-value float64) and calling Validate; also when Burst defaults/promotions make the subsequent burst check fire.","commonSituations":"Forgetting to set Requests because it is a float64 and the zero value looks like 'unset'; loading rate-limit numbers from config/env where an empty string parses to 0; copy-pasting a config struct without fields.","solutions":["Set Requests to a positive number, e.g. RateLimiterConfig{Requests: 100, Window: time.Minute}.","Check the error returned by Validate instead of ignoring it, since Validate also mutates Requests to the 60 default.","Validate config-loaded values before wiring them into RateLimiterConfig (reject 0/negative at parse time)."],"exampleFix":"// before\ncfg := &service.RateLimiterConfig{Window: time.Minute} // Requests == 0\n// after\ncfg := &service.RateLimiterConfig{Requests: 60, Window: time.Minute, Burst: 10}","handlingStrategy":"validation","validationCode":"if cfg.Requests <= 0 {\n\treturn fmt.Errorf(\"Requests must be > 0, got %f\", cfg.Requests)\n}\nif err := cfg.Validate(); err != nil { return err }","typeGuard":"func validRate(cfg *service.RateLimiterConfig) bool {\n\treturn cfg != nil && cfg.Requests > 0\n}","tryCatchPattern":"if err := cfg.Validate(); err != nil {\n\tif errors.Is(err, errInvalidRequestRate) {\n\t\tlog.Printf(\"rate limit config invalid, Validate applied default (60/min): %v\", err)\n\t}\n}","preventionTips":["Always set Requests explicitly — the zero value of float64 means 0 requests.","Check Validate's error return; Validate silently rewrites invalid values to defaults.","Validate config-file values at parse time, before constructing the limiter.","Cover limiter config with a table test asserting Requests > 0."],"tags":["rate-limiting","config","validation"],"backgroundTag":"invalid-rate-limit-config","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}