dotnet/orleans · error · ArgumentOutOfRangeException
Value must be positive or Timeout.InfiniteTimeSpan.
Error message
Value must be positive or Timeout.InfiniteTimeSpan.
What it means
Thrown by the MaxPauseBetweenOperationRetries setter on AzureStoragePolicyOptions when the value is <= TimeSpan.Zero and is not Timeout.InfiniteTimeSpan. This bounds the Azure SDK exponential-retry ceiling; a non-positive finite value would make no sense, so it is rejected with an ArgumentOutOfRangeException. Defaults to 1 minute when unset.
Source
Thrown at src/Azure/Shared/Storage/AzureStoragePolicyOptions.cs:56
public TimeSpan PauseBetweenCreationRetries { get; set; } = TimeSpan.FromSeconds(1);
/// <summary>
/// The base delay used by the Azure SDK exponential retry policy.
/// </summary>
public TimeSpan PauseBetweenOperationRetries { get; set; } = TimeSpan.FromSeconds(0.8);
/// <summary>
/// The maximum delay used by the Azure SDK exponential retry policy.
/// </summary>
public TimeSpan MaxPauseBetweenOperationRetries
{
get => this.maxPauseBetweenOperationRetries ?? TimeSpan.FromMinutes(1);
set
{
if (value <= TimeSpan.Zero && !value.Equals(Timeout.InfiniteTimeSpan))
{
throw new ArgumentOutOfRangeException(nameof(MaxPauseBetweenOperationRetries), value, "Value must be positive or Timeout.InfiniteTimeSpan.");
}
this.maxPauseBetweenOperationRetries = value;
}
}
public TimeSpan CreationTimeout
{
get => this.creationTimeout ?? TimeSpan.FromMilliseconds(this.PauseBetweenCreationRetries.TotalMilliseconds * this.MaxCreationRetries * 3);
set => SetIfValidTimeout(ref this.creationTimeout, value, nameof(CreationTimeout));
}
public TimeSpan OperationTimeout
{
get => this.operationTimeout ?? TimeSpan.FromSeconds(100);
set => SetIfValidTimeout(ref this.operationTimeout, value, nameof(OperationTimeout));
}
private static void SetIfValidTimeout(ref TimeSpan? field, TimeSpan value, string propertyName)View on GitHub (pinned to fca799fa70)
Solutions
- Set a positive TimeSpan (e.g. TimeSpan.FromMinutes(1)) or Timeout.InfiniteTimeSpan for no cap.
- If you want the default, simply do not assign the property (it defaults to 1 minute).
- Validate computed delay values before assignment.
Example fix
// before policy.MaxPauseBetweenOperationRetries = TimeSpan.Zero; // throws // after policy.MaxPauseBetweenOperationRetries = TimeSpan.FromMinutes(1); // or leave unset for the default
Defensive patterns
Strategy: validation
Validate before calling
static TimeSpan SafeMaxPause(TimeSpan v) =>
v > TimeSpan.Zero || v == Timeout.InfiniteTimeSpan ? v : throw new ArgumentOutOfRangeException(nameof(v)); Type guard
static bool IsValidMaxPause(TimeSpan v) => v > TimeSpan.Zero || v == Timeout.InfiniteTimeSpan;
Try / catch
catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("Value must be positive")) { /* pass a positive TimeSpan or Infinite */ } Prevention
- Leave MaxPauseBetweenOperationRetries unset to use the 1-minute default.
- Validate computed delays before assignment.
When it happens
Trigger: Assigning policy.MaxPauseBetweenOperationRetries = TimeSpan.Zero or a negative TimeSpan (e.g. TimeSpan.FromSeconds(-1)) in storage policy configuration.
Common situations: Misreading 0 as 'no cap'; computing a delay that underflows to negative; copying a config snippet that used TimeSpan.Zero intending 'default'.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Value cannot be null. (Parameter 'createClientCallback')
- Value cannot be null. (Parameter 'connectionString')
- Value cannot be null. (Parameter 'serviceUri')
- Value cannot be null. (Parameter 'tokenCredential')
- Value cannot be null. (Parameter 'azureSasCredential')
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/48d3ba8320fa1386.
Report an issue: GitHub.