dotnet/orleans · critical · InvalidOperationException

No Azure Table service client was configured. Set TableServi

Error message

No Azure Table service client was configured. Set TableServiceClient or call ConfigureTableServiceClient.

What it means

Thrown during AzureTableJournalStorageProvider.Initialize when AzureTableJournalStorageOptions.CreateClient is null, meaning no TableServiceClient was provided. The provider cannot connect to Azure Tables without a client, so it aborts silo initialization rather than failing on the first storage call.

Source

Thrown at src/Azure/Orleans.Journaling.AzureStorage/AzureTableJournalStorageProvider.cs:39

        IServiceProvider serviceProvider,
        ILogger<AzureTableJournalStorage> logger,
        AzureTableJournalStorageInstruments? instruments = null)
    {
        _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);
    }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Call one of options.ConfigureTableServiceClient(connectionString | Uri | Uri+credential) before startup.
  2. Set options.TableServiceClient directly with a prebuilt TableServiceClient.
  3. Verify your AddAzureTableJournaling configuration lambda actually invokes a ConfigureTableServiceClient overload.

Example fix

// before
builder.AddAzureTableJournaling(opts => { opts.TableName = "journal"; });
// after
builder.AddAzureTableJournaling(opts =>
{
    opts.TableName = "journal";
    opts.ConfigureTableServiceClient(builder.Configuration.GetConnectionString("AzureStorage"));
});
Defensive patterns

Strategy: validation

Validate before calling

if (options.CreateClient is null && options.TableServiceClient is null)
    throw new InvalidOperationException("Configure a TableServiceClient before startup.");

Type guard

static bool IsTableClientConfigured(AzureTableJournalStorageOptions o) => o.TableServiceClient is not null || o.CreateClient is not null;

Prevention

When it happens

Trigger: The options were registered (e.g. via AddAzureTableJournaling) but neither TableServiceClient was set nor any ConfigureTableServiceClient overload was called, then the silo lifecycle triggers Initialize.

Common situations: Forgetting to call ConfigureTableServiceClient in Program.cs; relying on a config section that did not bind credentials; misordering of configuration such that the client setup callback never ran.

Related errors


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