dotnet/orleans · error · ArgumentOutOfRangeException

MetadataOnlyConflictMaxBackoff must be non-negative.

Error message

MetadataOnlyConflictMaxBackoff must be non-negative.

What it means

AzureTableJournalStorageOptions.MetadataOnlyConflictMaxBackoff was set to a negative TimeSpan. The constructor (AzureTableJournalStorage.cs:1288) requires it non-negative (TimeSpan.Zero is allowed). This caps the exponential backoff used between metadata-only conflict retries. The argument blamed is `options`.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorage.cs:1290

            if (Options.CompactionSizeThreshold <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options), $"{nameof(AzureTableJournalStorageOptions.CompactionSizeThreshold)} must be positive.");
            }

            if (Options.MaxMetadataOnlyConflictRetries < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options), $"{nameof(AzureTableJournalStorageOptions.MaxMetadataOnlyConflictRetries)} must be non-negative.");
            }

            if (Options.MetadataOnlyConflictInitialBackoff < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(options), $"{nameof(AzureTableJournalStorageOptions.MetadataOnlyConflictInitialBackoff)} must be non-negative.");
            }

            if (Options.MetadataOnlyConflictMaxBackoff < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(options), $"{nameof(AzureTableJournalStorageOptions.MetadataOnlyConflictMaxBackoff)} must be non-negative.");
            }

            JournalFormatKey = journalFormatKey;
            TableClientProvider = tableClientProvider;
            Instruments = instruments;
        }

        public ILogger<AzureTableJournalStorage> Logger { get; }

        public AzureTableJournalStorageOptions Options { get; }

        public string? JournalFormatKey { get; }

        public TableClientProvider TableClientProvider { get; }

        public AzureTableJournalStorageInstruments Instruments { get; }
    }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Set MetadataOnlyConflictMaxBackoff to TimeSpan.Zero or a positive value (default 200 ms).
  2. Ensure the value is >= MetadataOnlyConflictInitialBackoff in practice to get a sensible schedule.
  3. Validate via IValidateOptions<T> at startup.

Example fix

// before
options.MetadataOnlyConflictMaxBackoff = TimeSpan.FromMilliseconds(-1);

// after
options.MetadataOnlyConflictMaxBackoff = AzureTableJournalStorageOptions.DEFAULT_METADATA_ONLY_CONFLICT_MAX_BACKOFF;
Defensive patterns

Strategy: validation

Validate before calling

if (options.MetadataOnlyConflictMaxBackoff < TimeSpan.Zero)
    throw new ArgumentOutOfRangeException(nameof(options.MetadataOnlyConflictMaxBackoff), "Must be non-negative");

Type guard

static bool IsValidMaxBackoff(TimeSpan v) => v >= TimeSpan.Zero;

Prevention

When it happens

Trigger: Configuring MetadataOnlyConflictMaxBackoff < TimeSpan.Zero; thrown at AzureTableJournalStorage.cs:1290.

Common situations: Negative TimeSpan from config binding; arithmetic that produced a negative cap; mistaking the cap for a duration to subtract.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/adcb05a47db1bb8b. Report an issue: GitHub.