{"record":{"id":"1e70b85bdfc03492","repo":"App-vNext/Polly","slug":"the-retryafter-parameter-must-be-a-timespan-greate","errorCode":null,"errorMessage":"The retryAfter parameter must be a TimeSpan greater than or equal to TimeSpan.Zero.","messagePattern":"The retryAfter parameter must be a TimeSpan greater than or equal to TimeSpan\\.Zero\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Polly/RateLimit/RateLimitRejectedException.cs","lineNumber":92,"sourceCode":"        : base(message) => SetRetryAfter(retryAfter);\n\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"RateLimitRejectedException\"/> class.\n    /// </summary>\n    /// <param name=\"message\">The message.</param>\n    /// <param name=\"retryAfter\">The timespan after which the operation may be retried.</param>\n    /// <param name=\"innerException\">The inner exception.</param>\n    public RateLimitRejectedException(TimeSpan retryAfter, string message, Exception innerException)\n        : base(message, innerException) => SetRetryAfter(retryAfter);\n\n    private static string DefaultMessage(TimeSpan retryAfter) =>\n        $\"The operation has been rate-limited and should be retried after {retryAfter}\";\n\n    private void SetRetryAfter(TimeSpan retryAfter)\n    {\n        if (retryAfter < TimeSpan.Zero)\n        {\n            throw new ArgumentOutOfRangeException(nameof(retryAfter), retryAfter, $\"The {nameof(retryAfter)} parameter must be a TimeSpan greater than or equal to TimeSpan.Zero.\");\n        }\n\n        RetryAfter = retryAfter;\n    }\n\n#if NETSTANDARD2_0\n    /// <summary>\n    /// Initializes a new instance of the <see cref=\"RateLimitRejectedException\"/> class.\n    /// </summary>\n    /// <param name=\"info\">The information.</param>\n    /// <param name=\"context\">The context.</param>\n    protected RateLimitRejectedException(SerializationInfo info, StreamingContext context)\n        : base(info, context)\n    {\n    }\n#endif\n}\n","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/RateLimit/RateLimitRejectedException.cs#L74-L110","documentation":"Thrown by RateLimitRejectedException.SetRetryAfter when retryAfter is less than TimeSpan.Zero. The exception's RetryAfter property must be a valid non-negative retry delay because callers use it to schedule the next attempt; a negative value would be meaningless.","triggerScenarios":"Constructing new RateLimitRejectedException(retryAfter, ...) (any overload chaining SetRetryAfter) with a TimeSpan that is negative. Typically happens when a custom retryAfterFactory or downstream code computes a delay that underflows.","commonSituations":"Clock skew or a subtracted offset producing a negative TimeSpan; a retry-after header parsed as a negative value; arithmetic on timestamps (e.g. serverTime - now) when now is ahead.","solutions":["Clamp the computed retry delay with TimeSpan.Max(value, TimeSpan.Zero) before constructing the exception.","Validate the source (e.g. Retry-After header) is non-negative before parsing to TimeSpan.","If the delay is genuinely unknown, pass TimeSpan.Zero rather than a negative value."],"exampleFix":"// before\nvar retryAfter = serverReset - DateTimeOffset.UtcNow;\nthrow new RateLimitRejectedException(retryAfter, msg, inner);\n// after\nvar retryAfter = TimeSpan.Max(serverReset - DateTimeOffset.UtcNow, TimeSpan.Zero);\nthrow new RateLimitRejectedException(retryAfter, msg, inner);","handlingStrategy":"validation","validationCode":"var retryAfter = serverReset - DateTimeOffset.UtcNow;\nif (retryAfter < TimeSpan.Zero) retryAfter = TimeSpan.Zero;\nthrow new RateLimitRejectedException(retryAfter, message, inner);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always clamp TimeSpan deltas with TimeSpan.Max(value, TimeSpan.Zero) before constructing rate-limit exceptions.","Parse and validate Retry-After header values as non-negative before converting to TimeSpan.","Account for clock skew when computing server-side reset times."],"tags":["rate-limit","argumentoutofrange","timespan","validation"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}