dotnet/orleans · error · ArgumentNullException

monitor

Error message

monitor

What it means

EventHubAdapterReceiver requires a non-null IQueueAdapterReceiverMonitor because it reports initialization success/failure, read latency, message counts, and shutdown metrics for each Event Hub partition. The monitor is called with TrackInitialization, TrackRead, TrackMessagesReceived, and TrackShutdown throughout the receiver lifecycle. Without it the runtime cannot detect slow or failing partitions.

Source

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

                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;
            }

            using var cancellation = new CancellationTokenSource(timeout);
            await Initialize(cancellation.Token);
        }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Pass a valid IQueueAdapterReceiverMonitor such as DefaultEventHubReceiverMonitor or a test implementation.
  2. If overriding ReceiverMonitorFactory in a subclass, ensure it never returns null.
  3. In tests, create a no-op or mock IQueueAdapterReceiverMonitor implementation.

Example fix

// before
var receiver = new EventHubAdapterReceiver(
    settings, cacheFactory, checkpointerFactory, loggerFactory,
    null /* monitor */, loadSheddingOptions, envStats);

// after
var dimensions = new EventHubReceiverMonitorDimensions { EventHubPartition = "0", EventHubPath = "myhub" };
var monitor = new DefaultEventHubReceiverMonitor(dimensions, orleansInstruments);
var receiver = new EventHubAdapterReceiver(
    settings, cacheFactory, checkpointerFactory, loggerFactory,
    monitor, loadSheddingOptions, envStats);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure monitor is non-null before constructing the receiver:
if (monitor is null)
    monitor = new DefaultEventHubReceiverMonitor(dimensions, orleansInstruments);

Prevention

When it happens

Trigger: Constructing EventHubAdapterReceiver with monitor set to null. In the factory path, the monitor is created by ReceiverMonitorFactory (defaulting to DefaultEventHubReceiverMonitor) during EventHubAdapterFactory.MakeReceiver and is always non-null. Fires on direct construction or if a custom ReceiverMonitorFactory returns null.

Common situations: Manual construction in tests without wiring a monitor; overriding ReceiverMonitorFactory in a subclass of EventHubAdapterFactory and having it return null; passing a test double that is unintentionally null.

Related errors


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