{"record":{"id":"f524511dd0b9d346","repo":"dotnet/orleans","slug":"cacheoptions","errorCode":null,"errorMessage":"cacheOptions","messagePattern":"cacheOptions","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubAdapterFactory.cs","lineNumber":123,"sourceCode":"        internal HashRingBasedPartitionedStreamQueueMapper EventHubQueueMapper => streamQueueMapper;\n\n        public EventHubAdapterFactory(\n            string name,\n            EventHubOptions ehOptions,\n            EventHubReceiverOptions receiverOptions,\n            EventHubStreamCachePressureOptions cacheOptions, \n            StreamCacheEvictionOptions cacheEvictionOptions,\n            StreamStatisticOptions statisticOptions,\n            IEventHubDataAdapter dataAdapter,\n            IServiceProvider serviceProvider,\n            ILoggerFactory loggerFactory,\n            IEnvironmentStatisticsProvider environmentStatisticsProvider)\n        {\n            this.Name = name;\n            this.cacheEvictionOptions = cacheEvictionOptions ?? throw new ArgumentNullException(nameof(cacheEvictionOptions));\n            this.statisticOptions = statisticOptions ?? throw new ArgumentNullException(nameof(statisticOptions));\n            this.ehOptions = ehOptions ?? throw new ArgumentNullException(nameof(ehOptions));\n            this.cacheOptions = cacheOptions?? throw new ArgumentNullException(nameof(cacheOptions));\n            this.dataAdapter = dataAdapter ?? throw new ArgumentNullException(nameof(dataAdapter));\n            this.receiverOptions = receiverOptions?? throw new ArgumentNullException(nameof(receiverOptions));\n            this.serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));\n            this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));\n            this.environmentStatisticsProvider = environmentStatisticsProvider;\n            this.orleansInstruments = serviceProvider.GetRequiredService<OrleansInstruments>();\n        }\n\n        public virtual void Init()\n        {\n            this.receivers = new ConcurrentDictionary<QueueId, EventHubAdapterReceiver>();\n\n            InitEventHubClient();\n\n            if (this.CacheFactory == null)\n            {\n                this.CacheFactory = CreateCacheFactory(this.cacheOptions).CreateCache;\n            }","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Streaming.EventHubs/Providers/Streams/EventHub/EventHubAdapterFactory.cs#L105-L141","documentation":"EventHubAdapterFactory rejects a null EventHubStreamCachePressureOptions in its constructor because cache-pressure monitoring needs concrete thresholds to apply back-pressure and avoid unbounded cache growth. This options object carries the slow-consuming flow-control threshold, pressure window size, and averaging monitor threshold. Without it the adapter cannot determine when to stop reading from Event Hub partitions.","triggerScenarios":"Constructing EventHubAdapterFactory directly with cacheOptions set to null, or a custom IQueueAdapterFactory/DI registration that supplies null for the EventHubStreamCachePressureOptions parameter. In the default EventHubAdapterFactory.Create path this is resolved via services.GetOptionByName<EventHubStreamCachePressureOptions>(name) which returns a non-null default, so this fires only on manual construction or a broken custom factory.","commonSituations":"Writing unit tests or a custom EventHubAdapterFactory subclass and passing null for cacheOptions; a DI container misconfiguration where a keyed/named options object is overridden with null; upgrading Orleans versions where the constructor signature changed and an outdated manual call site passes the wrong argument.","solutions":["If constructing the factory manually, pass a new EventHubStreamCachePressureOptions() (defaults are valid) instead of null.","If using the standard DI path, ensure AddEventHubStreams is called on the silo/client builder so that named EventHubStreamCachePressureOptions are registered.","If subclassing EventHubAdapterFactory, do not bypass the base constructor's null-check — pass all required options through."],"exampleFix":"// before\nvar factory = new EventHubAdapterFactory(\n    name, ehOptions, receiverOptions, null /* cacheOptions */, ...);\n\n// after\nvar factory = new EventHubAdapterFactory(\n    name, ehOptions, receiverOptions, new EventHubStreamCachePressureOptions(), ...);","handlingStrategy":"validation","validationCode":"// Before constructing EventHubAdapterFactory manually:\nif (cacheOptions is null)\n    throw new InvalidOperationException(\n        \"EventHubStreamCachePressureOptions must be configured. \" +\n        \"Call .Configure<EventHubStreamCachePressureOptions>(...) or use AddEventHubStreams.\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer EventHubAdapterFactory.Create(services, name) over manual construction — it resolves all options from DI with non-null defaults.","When subclassing EventHubAdapterFactory, always pass all constructor arguments through to the base constructor.","Register Event Hub streams via the AddEventHubStreams extension method to ensure all options objects are in DI."],"tags":["configuration","dependency-injection","eventhub","constructor","null-argument","cache-pressure"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}