{"record":{"id":"16f143653c850ee7","repo":"App-vNext/Polly","slug":"pertimespan-must-be-a-positive-timespan-16f143","errorCode":null,"errorMessage":"perTimeSpan must be a positive timespan.","messagePattern":"perTimeSpan must be a positive timespan\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Polly/RateLimit/RateLimitSyntax.cs","lineNumber":37,"sourceCode":"    /// </summary>\n    /// <param name=\"numberOfExecutions\">The number of executions (call it N) permitted per timespan.</param>\n    /// <param name=\"perTimeSpan\">How often N executions are permitted.</param>\n    /// <param name=\"maxBurst\">The maximum number of executions that will be permitted in a single burst (for example if none have been executed for a while).\n    /// This equates to the bucket-capacity of a token-bucket implementation.</param>\n    /// <returns>The policy instance.</returns>\n    public static RateLimitPolicy RateLimit(\n        int numberOfExecutions,\n        TimeSpan perTimeSpan,\n        int maxBurst)\n    {\n        if (numberOfExecutions < 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(numberOfExecutions), numberOfExecutions, $\"{nameof(numberOfExecutions)} per timespan must be an integer greater than or equal to 1.\");\n        }\n\n        if (perTimeSpan <= TimeSpan.Zero)\n        {\n            throw new ArgumentOutOfRangeException(nameof(perTimeSpan), perTimeSpan, $\"{nameof(perTimeSpan)} must be a positive timespan.\");\n        }\n\n        if (maxBurst < 1)\n        {\n            throw new ArgumentOutOfRangeException(nameof(maxBurst), maxBurst, $\"{nameof(maxBurst)} must be an integer greater than or equal to 1.\");\n        }\n\n        var onePer = TimeSpan.FromTicks(perTimeSpan.Ticks / numberOfExecutions);\n\n        if (onePer <= TimeSpan.Zero)\n        {\n            throw new ArgumentOutOfRangeException(nameof(perTimeSpan), perTimeSpan, \"The number of executions per timespan must be positive.\");\n        }\n\n        IRateLimiter rateLimiter = new LockFreeTokenBucketRateLimiter(onePer, maxBurst);\n\n        return new RateLimitPolicy(rateLimiter);\n    }","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/RateLimit/RateLimitSyntax.cs#L19-L55","documentation":"Thrown by RateLimitSyntax.RateLimit when perTimeSpan is less than or equal to TimeSpan.Zero. The window over which executions are counted must be positive for the token-bucket refill rate to be meaningful.","triggerScenarios":"Calling Policy.RateLimit(n, TimeSpan.Zero, ...) or Policy.RateLimit(n, TimeSpan.FromSeconds(-1), ...) on the sync non-generic overload.","commonSituations":"perTimeSpan read from config as 0 (e.g. \"0s\" or missing key); misconfigured POLICY_WINDOW environment variable; unit conversion yielding zero ticks.","solutions":["Set perTimeSpan to a positive TimeSpan (e.g. TimeSpan.FromSeconds(10)).","Sanitize config at startup: enforce perTimeSpan > TimeSpan.Zero before building the policy.","Check unit conversion (ms vs seconds) is not collapsing to zero."],"exampleFix":"// before\nvar policy = Policy.RateLimit(5, TimeSpan.Zero, 5);\n// after\nvar policy = Policy.RateLimit(5, TimeSpan.FromSeconds(10), 5);","handlingStrategy":"validation","validationCode":"var perTimeSpan = config.GetValue<TimeSpan>(\"RateLimit:Window\");\nif (perTimeSpan <= TimeSpan.Zero) throw new InvalidOperationException(\"RateLimit:Window must be positive.\");\nvar policy = Policy.RateLimit(numberOfExecutions, perTimeSpan, maxBurst);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Bind time-based config to TimeSpan and validate > TimeSpan.Zero at load.","Confirm the unit (seconds vs milliseconds) matches the config string.","Use IConfiguration validation or options pattern Validate() to fail fast at startup."],"tags":["rate-limit","argumentoutofrange","timespan","configuration"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}