Summary
When using the server-side .NET SDK in polling mode, every poll that receives an HTTP 304 Not Modified response (i.e. flags haven't changed since the last poll) throws and logs a NullReferenceException. It's caught by the generic exception handler so it doesn't crash the process, but it's logged as a Warning on effectively every polling interval once the SDK has initialized and flags are stable, and it incorrectly marks the data source status as Interrupted even though nothing is actually wrong.
Root cause
In FeatureRequestor.GetAllDataAsync():
public async Task<DataSetWithHeaders> GetAllDataAsync()
{
var res = await GetAsync(_allUri);
if (res is null)
{
return null; // <-- returns a null DataSetWithHeaders reference on 304
}
...
}
DataSetWithHeaders is a reference type (see IFeatureRequestor.cs), so on a 304 response GetAllDataAsync() returns a literal null, not an instance with a null DataSet property.
But in PollingDataSource.UpdateTaskAsync():
var dataAndHeaders = await _featureRequestor.GetAllDataAsync();
if (dataAndHeaders.DataSet is null) // <-- NullReferenceException here when dataAndHeaders itself is null
{
// This means it was cached, and alreadyInited was true
_dataSourceUpdates.UpdateStatus(DataSourceState.Valid, null);
}
This dereferences dataAndHeaders.DataSet without first checking whether dataAndHeaders itself is null, throwing an NRE that's then caught by the generic catch (Exception ex) block further down, logged as:
Polling for feature flag updates failed: System.NullReferenceException: Object reference not set to an instance of an object.
at LaunchDarkly.Sdk.Server.Internal.DataSources.PollingDataSource.UpdateTaskAsync()
...and reported via _dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, errorInfo) — even though a 304 is a perfectly healthy "no changes" response, not an interruption.
Impact
- Every poll where flags haven't changed logs a spurious
Warning (and, if the caller has enabled the SDK's Debug logging, a matching stack trace) that looks like a real failure but isn't.
DataSourceStatus is misreported as Interrupted instead of Valid for these no-op polls, which could affect consumers monitoring data source health via DataSourceStatusProvider.
- Flag evaluation itself is not affected, since this occurs after the flag store already has valid cached data from a prior successful poll.
Suggested fix
var dataAndHeaders = await _featureRequestor.GetAllDataAsync();
if (dataAndHeaders is null || dataAndHeaders.DataSet is null)
{
_dataSourceUpdates.UpdateStatus(DataSourceState.Valid, null);
}
Repro
- SDK:
LaunchDarkly.ServerSdk 8.16.0 (also confirmed present in current main of this repo as of 2026-09-03)
- Configuration:
Components.PollingDataSource(), any poll interval, running against the real LaunchDarkly polling endpoint (https://sdk.launchdarkly.com/sdk/latest-all)
- Trigger: let the client poll at least twice without any flag changes in between. The second (and every subsequent) poll that gets a 304 will throw.
Environment
- .NET 8, AWS Lambda
LaunchDarkly.ServerSdk 8.16.0
Happy to submit a PR with the one-line fix above if that's helpful.
Summary
When using the server-side .NET SDK in polling mode, every poll that receives an HTTP
304 Not Modifiedresponse (i.e. flags haven't changed since the last poll) throws and logs aNullReferenceException. It's caught by the generic exception handler so it doesn't crash the process, but it's logged as aWarningon effectively every polling interval once the SDK has initialized and flags are stable, and it incorrectly marks the data source status asInterruptedeven though nothing is actually wrong.Root cause
In
FeatureRequestor.GetAllDataAsync():DataSetWithHeadersis a reference type (seeIFeatureRequestor.cs), so on a 304 responseGetAllDataAsync()returns a literalnull, not an instance with anullDataSetproperty.But in
PollingDataSource.UpdateTaskAsync():This dereferences
dataAndHeaders.DataSetwithout first checking whetherdataAndHeadersitself is null, throwing an NRE that's then caught by the genericcatch (Exception ex)block further down, logged as:...and reported via
_dataSourceUpdates.UpdateStatus(DataSourceState.Interrupted, errorInfo)— even though a 304 is a perfectly healthy "no changes" response, not an interruption.Impact
Warning(and, if the caller has enabled the SDK's Debug logging, a matching stack trace) that looks like a real failure but isn't.DataSourceStatusis misreported asInterruptedinstead ofValidfor these no-op polls, which could affect consumers monitoring data source health viaDataSourceStatusProvider.Suggested fix
Repro
LaunchDarkly.ServerSdk8.16.0 (also confirmed present in currentmainof this repo as of 2026-09-03)Components.PollingDataSource(), any poll interval, running against the real LaunchDarkly polling endpoint (https://sdk.launchdarkly.com/sdk/latest-all)Environment
LaunchDarkly.ServerSdk8.16.0Happy to submit a PR with the one-line fix above if that's helpful.