dotnet/orleans · error · ArgumentNullException

Value cannot be null.

Error message

Value cannot be null.

What it means

Thrown by GetPartitionKeyForJournal when the AzureTableJournalStorageOptions.GetPartitionKey delegate has been set to null. The property defaults to a built-in mapper (DefaultGetPartitionKey), so this only fires when application code explicitly assigns null. The check guards the partition-key pipeline before it ever touches Azure Tables.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorageOptions.cs:109

    /// retries. The exponential schedule starts at <see cref="MetadataOnlyConflictInitialBackoff"/>
    /// and never exceeds this value. Defaults to 200 ms.
    /// </summary>
    public TimeSpan MetadataOnlyConflictMaxBackoff { get; set; } = DEFAULT_METADATA_ONLY_CONFLICT_MAX_BACKOFF;
    public static readonly TimeSpan DEFAULT_METADATA_ONLY_CONFLICT_MAX_BACKOFF = TimeSpan.FromMilliseconds(200);

    /// <summary>
    /// The optional delegate used to create a <see cref="TableServiceClient"/> instance.
    /// </summary>
    internal Func<CancellationToken, Task<TableServiceClient>>? CreateClient { get; private set; }

    internal string GetPartitionKeyForJournal(JournalId journalId)
    {
        if (journalId.IsDefault)
        {
            throw new ArgumentException("The journal id must not be the default value.", nameof(journalId));
        }

        var mapper = GetPartitionKey ?? throw new ArgumentNullException(nameof(GetPartitionKey));
        var partitionKey = mapper(journalId);
        ArgumentException.ThrowIfNullOrWhiteSpace(partitionKey);
        ValidatePartitionKey(partitionKey, nameof(partitionKey));
        return partitionKey;
    }

    internal static string GetDefaultPartitionKey(JournalId journalId)
    {
        if (journalId.IsDefault)
        {
            throw new ArgumentException("The journal id must not be the default value.", nameof(journalId));
        }

        // Percent-encoding escapes every character disallowed in partition keys ('/', '\', '#', '?',
        // control characters) and is reversible.
        var partitionKey = Uri.EscapeDataString(journalId.Value);
        ValidatePartitionKey(partitionKey, nameof(journalId));
        return partitionKey;

View on GitHub (pinned to fca799fa70)

Solutions

  1. Remove the assignment that sets options.GetPartitionKey to null; leave the default mapper in place.
  2. If you need a custom mapper, assign a non-null Func<JournalId, string> that returns a valid partition key.
  3. Restore the default with options.GetPartitionKey = AzureTableJournalStorageOptions.GetDefaultPartitionKey (via the public property default).

Example fix

// before
options.GetPartitionKey = null;
// after
// (omit the line entirely, or:)
options.GetPartitionKey = journalId => AzureTableJournalStorageOptions.GetDefaultPartitionKey(journalId);
Defensive patterns

Strategy: validation

Validate before calling

if (options.GetPartitionKey is null)
    throw new InvalidOperationException("GetPartitionKey must not be null; leave default or set a mapper.");

Type guard

static bool HasPartitionKeyMapper(AzureTableJournalStorageOptions o) => o.GetPartitionKey is not null;

Prevention

When it happens

Trigger: Calling code sets options.GetPartitionKey = null (or a config binder nulls it), then any operation that resolves a journal partition key (read, append, replace, list) invokes GetPartitionKeyForJournal and hits the null-coalescing throw at AzureTableJournalStorageOptions.cs:109.

Common situations: A developer overrides the partition-key mapper and later sets it to null to 'reset' it; an options validator or post-configuration step nulls the delegate; reflection/JSON config binding supplies null for the Func property.

Related errors


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