dotnet/orleans · error · ArgumentOutOfRangeException

MetadataOnlyConflictInitialBackoff must be non-negative.

Error message

MetadataOnlyConflictInitialBackoff must be non-negative.

What it means

Thrown during AzureBlobJournalStorageShared construction when AzureBlobJournalStorageOptions.MetadataOnlyConflictInitialBackoff is negative. This TimeSpan is the seed delay for the exponential backoff applied between metadata-only conflict retries. A negative duration is invalid and is rejected at construction time. TimeSpan.Zero is allowed and disables backoff.

Source

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

            AzureBlobJournalStorageInstruments instruments,
            string? mimeType = null,
            string? journalFormatKey = null)
        {
            ArgumentNullException.ThrowIfNull(logger);
            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; }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Set MetadataOnlyConflictInitialBackoff to TimeSpan.Zero or a positive value such as the default 10 ms.
  2. Add an IValidateOptions<AzureBlobJournalStorageOptions> to catch negative TimeSpans at startup.
  3. If backoff is unwanted, use TimeSpan.Zero rather than a negative value.

Example fix

// before
options.MetadataOnlyConflictInitialBackoff = TimeSpan.FromMilliseconds(-5);

// after
options.MetadataOnlyConflictInitialBackoff = TimeSpan.Zero; // retry immediately
Defensive patterns

Strategy: validation

Validate before calling

if (options.MetadataOnlyConflictInitialBackoff < TimeSpan.Zero)
    throw new ArgumentOutOfRangeException(nameof(options.MetadataOnlyConflictInitialBackoff));
// recommended: register IValidateOptions<AzureBlobJournalStorageOptions>
services.AddOptions<AzureBlobJournalStorageOptions>()
    .Validate(o => o.MetadataOnlyConflictInitialBackoff >= TimeSpan.Zero, "InitialBackoff must be non-negative");

Prevention

When it happens

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

Common situations: Loading the value from configuration where a missing key deserializes to a sentinel; arithmetic that subtracts TimeSpans yielding a negative result; confusing initial backoff with max backoff and entering a negative seed.

Related errors


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