dotnet/orleans · critical · InvalidOperationException
Session created from configuration 'CassandraClusteringOptio
Error message
Session created from configuration 'CassandraClusteringOptions' is null.
What it means
InvalidOperationException thrown inside InitializeMembershipTable when the user-supplied delegate CassandraClusteringOptions.CreateSessionAsync returns a null ISession. Orleans requires a valid Cassandra session; a null return indicates a misconfigured factory. The message names the options type so the misconfiguration is identifiable.
Source
Thrown at src/Cassandra/Orleans.Clustering.Cassandra/CassandraClusteringTable.cs:47
IServiceProvider serviceProvider)
{
_clusterOptions = clusterOptions.Value;
_options = options.Value;
_identifier = $"{_clusterOptions.ServiceId}-{_clusterOptions.ClusterId}";
_serviceProvider = serviceProvider;
_ttlSeconds = _options.GetCassandraTtlSeconds(clusterMembershipOptions.Value);
}
private ISession Session => _session ?? throw new InvalidOperationException(NotInitializedMessage);
private OrleansQueries Queries => _queries ?? throw new InvalidOperationException(NotInitializedMessage);
async Task IMembershipTable.InitializeMembershipTable(bool tryInitTableVersion)
{
_session = await _options.CreateSessionAsync(_serviceProvider);
if (_session is null)
{
throw new InvalidOperationException($"Session created from configuration '{nameof(CassandraClusteringOptions)}' is null.");
}
_queries = await OrleansQueries.CreateInstance(_session);
await _queries.EnsureTableExistsAsync(_options.InitializeRetryMaxDelay, _ttlSeconds);
if (tryInitTableVersion)
await _queries.EnsureClusterVersionExistsAsync(_options.InitializeRetryMaxDelay, _identifier);
}
async Task IMembershipTable.DeleteMembershipTableEntries(string clusterId)
{
if (string.Compare(clusterId, _clusterOptions.ClusterId, StringComparison.InvariantCultureIgnoreCase) != 0)
{
throw new ArgumentException(
$"Cluster id {clusterId} does not match CassandraClusteringTable value of '{_clusterOptions.ClusterId}'.",
nameof(clusterId));
}View on GitHub (pinned to fca799fa70)
Solutions
- Provide a CreateSessionAsync that always returns a non-null ISession (Cluster.Builder().AddContactPoint(...).Build().Connect(keyspace)).
- Verify the session-creation dependencies (contact points, credentials, keyspace) are configured in CassandraClusteringOptions.
- Throw a descriptive exception from inside CreateSessionAsync when session creation genuinely fails, instead of returning null.
Example fix
// before
options.CreateSessionAsync = _ => Task.FromResult<ISession>(null!); // null -> this throw
// after
options.CreateSessionAsync = async sp =>
{
var cfg = sp.GetRequiredService<IOptions<CassandraConfig>>().Value;
var cluster = Cluster.Builder()
.AddContactPoints(cfg.ContactPoints)
.WithCredentials(cfg.User, cfg.Password)
.Build();
return await cluster.ConnectAsync(cfg.Keyspace);
}; Defensive patterns
Strategy: validation
Validate before calling
options.CreateSessionAsync = async sp =>
{
var cfg = sp.GetRequiredService<IOptions<CassandraConfig>>().Value;
var cluster = Cluster.Builder().AddContactPoints(cfg.ContactPoints)
.WithCredentials(cfg.User, cfg.Password).Build();
var session = await cluster.ConnectAsync(cfg.Keyspace);
return session ?? throw new InvalidOperationException("session null");
}; Type guard
static async Task<ISession> NonNullSession(Func<Task<ISession?>> factory) =>
await factory() ?? throw new InvalidOperationException("session factory returned null"); Try / catch
try { await table.InitializeMembershipTable(true); }
catch (InvalidOperationException ex) when (ex.Message.Contains("is null"))
{ logger.LogCritical(ex, "Cassandra session factory returned null"); throw; } Prevention
- Never return null from CreateSessionAsync
- Validate contact points/keyspace/credentials at build time
- Throw a descriptive exception inside the factory on failure
When it happens
Trigger: CassandraClusteringOptions.CreateSessionAsync returns null. This delegate is responsible for building the ISession (cluster/builder); if it returns null, the table cannot proceed and initialization aborts before OrleansQueries is built.
Common situations: A custom CreateSessionAsync implementation with a missing return path (e.g. returns null on a not-found config), the default factory failing silently, or a DI scope where the session-creation service is not registered. Also seen when copy-pasting a sample that left the factory incomplete.
Related errors
- This instance has not been initialized. Ensure that Initiali
- Cluster id {clusterId} does not match CassandraClusteringTab
- Session created from configuration 'CassandraClusteringOptio
- Could not find cluster version entry for {this._partitionId}
- Invalid {nameof(AdoNetClusteringClientOptions)} values for {
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/20b31e58d5e345e0.
Report an issue: GitHub.