dotnet/orleans · error · ArgumentException

Cluster id {clusterId} does not match CassandraClusteringTab

Error message

Cluster id {clusterId} does not match CassandraClusteringTable value of '{_clusterOptions.ClusterId}'.

What it means

ArgumentException from DeleteMembershipTableEntries when the clusterId argument does not match the configured ClusterId (case-insensitive, InvariantCulture). The table is partitioned/identified by ClusterId, so deleting entries for a different cluster id is rejected to prevent cross-cluster data loss.

Source

Thrown at src/Cassandra/Orleans.Clustering.Cassandra/CassandraClusteringTable.cs:62

        _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));
        }

        await Session.ExecuteAsync(await Queries.DeleteMembershipTableEntries(_identifier));
    }

    async Task<bool> IMembershipTable.InsertRow(MembershipEntry entry, TableVersion tableVersion)
    {
        // Prevent duplicate rows
        var existingRow = await ((IMembershipTable)this).ReadRow(entry.SiloAddress);
        if (existingRow is not null)
        {
            if (existingRow.Version.Version >= tableVersion.Version)
            {
                return false;
            }

View on GitHub (pinned to fca799fa70)

Solutions

  1. Pass the same ClusterId that is configured in ClusterOptions (resolve IOptions<ClusterOptions> and use its ClusterId).
  2. Align your tooling's cluster id with the running silo's configured cluster id before issuing a delete.
  3. Avoid hardcoding cluster ids; source them from the same configuration the silo uses.

Example fix

// before
await table.DeleteMembershipTableEntries("old-cluster"); // throws

// after
var clusterId = host.Services.GetRequiredService<IOptions<ClusterOptions>>().Value.ClusterId;
await table.DeleteMembershipTableEntries(clusterId);
Defensive patterns

Strategy: validation

Validate before calling

var clusterId = host.Services.GetRequiredService<IOptions<ClusterOptions>>().Value.ClusterId;
if (!string.Equals(clusterId, configured, StringComparison.InvariantCultureIgnoreCase))
    throw new ArgumentException("cluster id mismatch");
await table.DeleteMembershipTableEntries(clusterId);

Type guard

static bool ClusterIdMatches(string a, string b) =>
    string.Equals(a, b, StringComparison.InvariantCultureIgnoreCase);

Prevention

When it happens

Trigger: Calling IMembershipTable.DeleteMembershipTableEntries(clusterId) with a clusterId that differs from IOptions<ClusterOptions>.ClusterId used to construct the table. The comparison uses string.Compare with InvariantCultureIgnoreCase.

Common situations: Calling DeleteMembershipTableEntries with a stale/hardcoded cluster id after renaming the cluster, or a management tool passing a cluster id from config that doesn't match the silo's ClusterOptions. Case differences are tolerated, but any other difference throws.

Related errors


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