dotnet/orleans · error · ArgumentOutOfRangeException

MetadataOnlyConflictMaxBackoff must be non-negative.

Error message

MetadataOnlyConflictMaxBackoff must be non-negative.

What it means

Thrown during AzureBlobJournalStorageShared construction when AzureBlobJournalStorageOptions.MetadataOnlyConflictMaxBackoff is negative. This TimeSpan caps the exponential backoff used between metadata-only conflict retries. A negative cap is invalid; TimeSpan.Zero is the minimum sensible value.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureBlobJournalStorage.cs:1147

            ArgumentNullException.ThrowIfNull(options);
            ArgumentNullException.ThrowIfNull(blobClientProvider);

            Logger = logger;
            Options = options.Value;
            ArgumentNullException.ThrowIfNull(Options);
            if (Options.MaxMetadataOnlyConflictRetries < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(options), $"{nameof(AzureBlobJournalStorageOptions.MaxMetadataOnlyConflictRetries)} must be non-negative.");
            }

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

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

            MimeType = mimeType;
            JournalFormatKey = journalFormatKey;
            BlobClientProvider = blobClientProvider;
            Instruments = instruments;
        }

        public ILogger<AzureBlobJournalStorage> Logger { get; }

        public AzureBlobJournalStorageOptions Options { get; }

        public string? MimeType { get; }

        public string? JournalFormatKey { get; }

        public BlobClientProvider BlobClientProvider { get; }
        public AzureBlobJournalStorageInstruments Instruments { get; }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Set MetadataOnlyConflictMaxBackoff to a positive value such as the default 200 ms, or TimeSpan.Zero.
  2. Ensure max backoff >= initial backoff to keep the exponential schedule meaningful.
  3. Register an IValidateOptions<AzureBlobJournalStorageOptions> to fail fast at startup.

Example fix

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

// after
options.MetadataOnlyConflictMaxBackoff = TimeSpan.FromMilliseconds(200);
Defensive patterns

Strategy: validation

Validate before calling

if (options.MetadataOnlyConflictMaxBackoff < TimeSpan.Zero)
    throw new ArgumentOutOfRangeException(nameof(options.MetadataOnlyConflictMaxBackoff));
// ensure max >= initial
services.AddOptions<AzureBlobJournalStorageOptions>()
    .Validate(o => o.MetadataOnlyConflictMaxBackoff >= TimeSpan.Zero
        && o.MetadataOnlyConflictMaxBackoff >= o.MetadataOnlyConflictInitialBackoff,
        "MaxBackoff must be non-negative and >= InitialBackoff");

Prevention

When it happens

Trigger: Setting options.MetadataOnlyConflictMaxBackoff to a value less than TimeSpan.Zero and then constructing the provider or shared storage object. Validation runs in the AzureBlobJournalStorageShared constructor.

Common situations: Misconfiguring from JSON where the field is omitted and a default-fallback sets a negative value; setting max backoff lower than initial backoff and entering negative territory via subtraction; copy-paste error from initial backoff.

Related errors


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