dotnet/orleans · error · ArgumentNullException

checkpointerFactory

Error message

checkpointerFactory

What it means

EventHubAdapterReceiver requires a non-null checkpointerFactory delegate because it is called during Initialize to create an IStreamQueueCheckpointer<string> that loads and persists the Event Hub offset for the partition. Without checkpointing the receiver would re-read from the start of the partition on every restart, causing duplicate processing. The factory is invoked as checkpointerFactory(settings.Partition, cancellationToken) to produce the checkpointer.

Source

Thrown at src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubAdapterReceiver.cs:103

                monitor,
                loadSheddingOptions,
                environmentStatisticsProvider,
                eventHubReceiverFactory)
        {
        }

        public EventHubAdapterReceiver(EventHubPartitionSettings settings,
            Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> cacheFactory,
            Func<string, CancellationToken, Task<IStreamQueueCheckpointer<string>>> checkpointerFactory,
            ILoggerFactory loggerFactory,
            IQueueAdapterReceiverMonitor monitor,
            LoadSheddingOptions loadSheddingOptions,
            IEnvironmentStatisticsProvider environmentStatisticsProvider,
            Func<EventHubPartitionSettings, string, ILogger, IEventHubReceiver>? eventHubReceiverFactory = null)
        {
            this.settings = settings ?? throw new ArgumentNullException(nameof(settings));
            this.cacheFactory = cacheFactory ?? throw new ArgumentNullException(nameof(cacheFactory));
            this.checkpointerFactory = checkpointerFactory ?? throw new ArgumentNullException(nameof(checkpointerFactory));
            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
            this.logger = this.loggerFactory.CreateLogger<EventHubAdapterReceiver>();
            this.monitor = monitor ?? throw new ArgumentNullException(nameof(monitor));
            this.loadSheddingOptions = loadSheddingOptions ?? throw new ArgumentNullException(nameof(loadSheddingOptions));
            this.environmentStatisticsProvider = environmentStatisticsProvider;
            this.eventHubReceiverFactory = eventHubReceiverFactory == null ? EventHubAdapterReceiver.CreateReceiver : eventHubReceiverFactory;
        }

        public async Task Initialize(TimeSpan timeout)
        {
            LogInfoInitializingEventHubPartition(this.settings.Hub.EventHubName, this.settings.Partition);

            // if receiver was already running, do nothing
            if (ReceiverRunning == Interlocked.Exchange(ref this.receiverState, ReceiverRunning))
            {
                return;
            }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Ensure a stream checkpointer is configured, e.g., by calling the appropriate checkpointer configuration extension on the Event Hub stream provider.
  2. If constructing manually, pass a Func<string, CancellationToken, Task<IStreamQueueCheckpointer<string>>> that returns a valid checkpointer (e.g., a mock in tests).
  3. Verify StreamCheckpointerConfigurationValidator passes during silo startup — it checks for IStreamQueueCheckpointerFactory keyed services.

Example fix

// before
var receiver = new EventHubAdapterReceiver(
    settings, cacheFactory, null /* checkpointerFactory */, ...);

// after
Func<string, CancellationToken, Task<IStreamQueueCheckpointer<string>>> checkpointerFactory =
    async (partition, ct) =>
    {
        var checkpointer = new MockCheckpointer();
        await checkpointer.Load(ct);
        return checkpointer;
    };
var receiver = new EventHubAdapterReceiver(
    settings, cacheFactory, checkpointerFactory, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Verify checkpointer factory is non-null:
if (checkpointerFactory is null)
    throw new InvalidOperationException(
        "A checkpointer factory is required. Ensure IStreamQueueCheckpointerFactory " +
        "is registered in DI for this stream provider.");

Prevention

When it happens

Trigger: Constructing EventHubAdapterReceiver with checkpointerFactory set to null. In the factory path, the checkpointer factory is passed from EventHubAdapterFactory.MakeReceiver as (partition, ct) => this.checkpointerFactory.Create(partition, ct), where checkpointerFactory is resolved from keyed DI services. Fires on direct construction or when the IStreamQueueCheckpointerFactory is not registered in DI.

Common situations: Forgetting to register a checkpointer provider (e.g., Azure Blob Storage checkpointer) in the Event Hub stream configuration; manual construction in tests without a checkpointer; the IStreamQueueCheckpointerFactory keyed service is missing from DI, though in that case StreamCheckpointerConfigurationValidator would typically catch it first.

Related errors


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