dotnet/orleans · error · InvalidOperationException
The configured Azure Table service client factory returned n
Error message
The configured Azure Table service client factory returned null.
What it means
Thrown during Initialize when the configured CreateClient factory delegate returns null after awaiting. The contract requires the factory to produce a non-null TableServiceClient; a null result indicates a broken factory and is rejected immediately.
Source
Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorageProvider.cs:43
_options = options.Value;
var journalFormatKey = ValidateJournalFormatKey(managerOptions.Value.JournalFormatKey);
ValidateJournalFormat(serviceProvider, journalFormatKey);
_shared = new AzureTableJournalStorage.AzureTableJournalStorageShared(
logger,
options,
_tableClientProvider,
instruments ?? AzureTableJournalStorageInstruments.CreateForDirectConstruction(),
journalFormatKey);
}
private async Task Initialize(CancellationToken cancellationToken)
{
var createClient = _options.CreateClient
?? throw new InvalidOperationException(
$"No Azure Table service client was configured. Set {nameof(AzureTableJournalStorageOptions.TableServiceClient)} " +
$"or call {nameof(AzureTableJournalStorageOptions.ConfigureTableServiceClient)}.");
var client = await createClient(cancellationToken).ConfigureAwait(false)
?? throw new InvalidOperationException("The configured Azure Table service client factory returned null.");
var table = client.GetTableClient(_options.TableName);
await table.CreateIfNotExistsAsync(cancellationToken).ConfigureAwait(false);
_tableClientProvider.SetTableClient(table);
}
public IJournalStorage CreateStorage(JournalId journalId)
{
if (journalId.IsDefault)
{
throw new ArgumentException("The journal id must not be the default value.", nameof(journalId));
}
return new AzureTableJournalStorage(_shared, journalId);
}
public async IAsyncEnumerable<JournalId> ListAsync(
JournalId prefix = default,
[EnumeratorCancellation] CancellationToken cancellationToken = default)View on GitHub (pinned to fca799fa70)
Solutions
- Ensure the factory always returns a valid TableServiceClient instance; throw inside the factory if construction fails.
- Replace a null-returning factory with a simpler ConfigureTableServiceClient overload (connection string / Uri / credential).
- Add a null check inside the factory that throws a descriptive exception before returning.
Example fix
// before options.ConfigureTableServiceClient(ct => Task.FromResult<TableServiceClient>(null!)); // after options.ConfigureTableServiceClient(ct => Task.FromResult(new TableServiceClient(connectionString)));
Defensive patterns
Strategy: validation
Validate before calling
var client = await options.CreateClient!(ct);
if (client is null) throw new InvalidOperationException("Client factory returned null."); Type guard
static bool FactoryReturnsNonNull(Func<CancellationToken, Task<TableServiceClient>> f, CancellationToken ct) => f(ct).GetAwaiter().GetResult() is not null;
Prevention
- Inside a custom factory, never return null; throw on construction failure.
- Prefer the built-in ConfigureTableServiceClient overloads.
- Unit-test the factory in isolation to confirm it yields a client.
When it happens
Trigger: A custom ConfigureTableServiceClient callback returns null (e.g. ct => Task.FromResult<TableServiceClient>(null)) due to a failed internal client construction or a misplaced default.
Common situations: A factory that conditionally returns null on missing config instead of throwing; a dependency-injection resolver returning null; a refactor that dropped the 'new TableServiceClient(...)' expression.
Related errors
- No Azure Table service client was configured. Set TableServi
- Value cannot be null.
- Journal format key '{journalFormatKey}' requires keyed servi
- Journal format key '{journalFormatKey}' resolved format '{jo
- The configured journal format key must be non-empty.
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/a2491e4f83877b12.
Report an issue: GitHub.