{"record":{"id":"110c5cafaef44db8","repo":"App-vNext/Polly","slug":"value-must-be-greater-than-zero-110c5c","errorCode":null,"errorMessage":"Value must be greater than zero.","messagePattern":"Value must be greater than zero\\.","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Polly/CircuitBreaker/CircuitBreakerTResultSyntax.cs","lineNumber":188,"sourceCode":"    /// </summary>\n    /// <typeparam name=\"TResult\">The type of the result.</typeparam>\n    /// <param name=\"policyBuilder\">The policy builder.</param>\n    /// <param name=\"handledEventsAllowedBeforeBreaking\">The number of exceptions or handled results that are allowed before opening the circuit.</param>\n    /// <param name=\"durationOfBreak\">The duration the circuit will stay open before resetting.</param>\n    /// <param name=\"onBreak\">The action to call when the circuit transitions to an <see cref=\"CircuitState.Open\"/> state.</param>\n    /// <param name=\"onReset\">The action to call when the circuit resets to a <see cref=\"CircuitState.Closed\"/> state.</param>\n    /// <param name=\"onHalfOpen\">The action to call when the circuit transitions to <see cref=\"CircuitState.HalfOpen\"/> state, ready to try action executions again. </param>\n    /// <returns>The policy instance.</returns>\n    /// <remarks>(see \"Release It!\" by Michael T. Nygard fi).</remarks>\n    /// <exception cref=\"ArgumentOutOfRangeException\">handledEventsAllowedBeforeBreaking;Value must be greater than zero.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"onBreak\"/> is <see langword=\"null\"/>.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"onReset\"/> is <see langword=\"null\"/>.</exception>\n    /// <exception cref=\"ArgumentNullException\">Thrown when <paramref name=\"onHalfOpen\"/> is <see langword=\"null\"/>.</exception>\n    public static CircuitBreakerPolicy<TResult> CircuitBreaker<TResult>(this PolicyBuilder<TResult> policyBuilder, int handledEventsAllowedBeforeBreaking, TimeSpan durationOfBreak, Action<DelegateResult<TResult>, CircuitState, TimeSpan, Context> onBreak, Action<Context> onReset, Action onHalfOpen)\n    {\n        if (handledEventsAllowedBeforeBreaking <= 0)\n        {\n            throw new ArgumentOutOfRangeException(nameof(handledEventsAllowedBeforeBreaking), \"Value must be greater than zero.\");\n        }\n\n        if (durationOfBreak < TimeSpan.Zero)\n        {\n            throw new ArgumentOutOfRangeException(nameof(durationOfBreak), \"Value must be greater than zero.\");\n        }\n\n        if (onBreak == null)\n        {\n            throw new ArgumentNullException(nameof(onBreak));\n        }\n\n        if (onReset == null)\n        {\n            throw new ArgumentNullException(nameof(onReset));\n        }\n\n        if (onHalfOpen == null)","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly/CircuitBreaker/CircuitBreakerTResultSyntax.cs#L170-L206","documentation":"Thrown by the legacy generic CircuitBreaker<TResult> syntax when 'handledEventsAllowedBeforeBreaking' is <= 0. This is the result-handling equivalent of the non-generic breaker: it counts both handled exceptions and handled results before opening. The ArgumentOutOfRangeException is raised at policy construction.","triggerScenarios":"Calling Policy<TResult>.Handle<...>().CircuitBreaker(handledEventsAllowedBeforeBreaking, durationOfBreak, onBreak, onReset, onHalfOpen) with handledEventsAllowedBeforeBreaking <= 0. Often hit when a threshold read from config is 0 or unset.","commonSituations":"Binding the threshold from IConfiguration with a missing key (resolves to 0); sharing a constant with a no-op policy that intentionally uses 0; misunderstanding that the count covers both faulted results and exceptions.","solutions":["Pass handledEventsAllowedBeforeBreaking >= 1.","Validate/clamp the sourced value before building: var threshold = config.GetValue<int?>(\"Breaker:Threshold\") ?? 5;.","Confirm the parameter refers to handled events (results OR exceptions), not retries."],"exampleFix":"// before\nvar policy = Policy<Result>\n    .Handle<HttpException>()\n    .OrResult(r => r.IsFailure)\n    .CircuitBreaker(0, TimeSpan.FromSeconds(30), onBreak, onReset, onHalfOpen);\n\n// after\nvar threshold = config.GetValue<int?>(\"Breaker:Threshold\") ?? 5;\nvar policy = Policy<Result>\n    .Handle<HttpException>()\n    .OrResult(r => r.IsFailure)\n    .CircuitBreaker(threshold, TimeSpan.FromSeconds(30), onBreak, onReset, onHalfOpen);","handlingStrategy":"validation","validationCode":"if (handledEventsAllowedBeforeBreaking <= 0) throw new ArgumentOutOfRangeException(nameof(handledEventsAllowedBeforeBreaking));\nvar policy = Policy<TResult>.Handle<X>().CircuitBreaker(handledEventsAllowedBeforeBreaking, durationOfBreak, ...);","typeGuard":"static int NormalizeThreshold(int v) => v <= 0 ? 1 : v;","tryCatchPattern":"try { var policy = builder.CircuitBreaker(n, ts, ...); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"handledEventsAllowedBeforeBreaking\") { /* surface config error */ throw; }","preventionTips":["Validate thresholds at app startup from IConfiguration and fail fast.","Document that the count covers both handled results and exceptions.","Unit-test the builder with value=1 to lock the minimum."],"tags":["circuit-breaker","configuration","argument-validation","csharp","generics","legacy-api"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}