dotnet/orleans · error · ArgumentNullException

cacheFactory

Error message

cacheFactory

What it means

EventHubAdapterReceiver requires a non-null cacheFactory delegate because it is called during Initialize to create the IEventHubQueueCache for each partition — the cache holds incoming EventData as CachedMessage objects and serves them to stream consumers via cursors. Without it the receiver cannot buffer any messages and the Initialize method would fail with a NullReferenceException at the cacheFactory invocation.

Source

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

                loggerFactory,
                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 EventHubAdapterFactory.Init() is called before any receiver is created, as Init sets CacheFactory via CreateCacheFactory.
  2. If constructing EventHubAdapterReceiver directly, pass a valid Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> that creates an EventHubQueueCache.
  3. If overriding CreateCacheFactory in a subclass, ensure it returns a non-null IEventHubQueueCacheFactory.

Example fix

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

// after
Func<string, IStreamQueueCheckpointer<string>, ILoggerFactory, IEventHubQueueCache> cacheFactory =
    (partition, checkpointer, loggerFactory) =>
        new EventHubQueueCache(partition, 1000, bufferPool, dataAdapter, evictionStrategy, checkpointer, logger, cacheMonitor, null, null);
var receiver = new EventHubAdapterReceiver(
    settings, cacheFactory, checkpointerFactory, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure CacheFactory is set before creating receivers:
if (factory.CacheFactory is null)
    throw new InvalidOperationException(
        "CacheFactory is not set. Call EventHubAdapterFactory.Init() first.");

Prevention

When it happens

Trigger: Constructing EventHubAdapterReceiver with cacheFactory set to null. In the factory path, CacheFactory is set from CreateCacheFactory(cacheOptions).CreateCache during EventHubAdapterFactory.Init, and passed through MakeReceiver. Fires only on direct construction or a custom factory that leaves CacheFactory unset.

Common situations: Manual construction in tests without wiring up a cache factory; a subclass of EventHubAdapterFactory that overrides Init or CreateCacheFactory incorrectly and produces a null CacheFactory; calling the EventHubAdapterReceiver constructor before EventHubAdapterFactory.Init has run (which sets CacheFactory).

Related errors


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