dotnet/orleans · critical · InvalidOperationException
The membership table does not contain a version row.
Error message
The membership table does not contain a version row.
What it means
Thrown by AzureBasedMembershipTable.Convert when, after iterating all entries, no table version row was found (tableVersion stayed null). Orleans requires exactly one version row per partition to coordinate membership updates; its absence means the table is uninitialized or the version row was deleted. InvalidOperationException is thrown and the outer catch logs via LogErrorParsingMembershipTableData.
Source
Thrown at src/Azure/Orleans.Clustering.AzureStorage/AzureBasedMembershipTable.cs:202
continue;
}
else
{
try
{
MembershipEntry membershipEntry = Parse(tableEntry);
memEntries.Add(new Tuple<MembershipEntry, string>(membershipEntry, tuple.ETag));
}
catch (Exception exc)
{
LogErrorParsingMembershipTableDataIgnoring(exc, tableEntry);
}
}
}
var data = new MembershipTableData(
memEntries,
tableVersion ?? throw new InvalidOperationException("The membership table does not contain a version row."));
return data;
}
catch (Exception exc)
{
LogErrorParsingMembershipTableData(exc, new(entries));
throw;
}
}
private static MembershipEntry Parse(SiloInstanceTableEntry tableEntry)
{
var parse = new MembershipEntry
{
HostName = tableEntry.HostName!,
Status = (SiloStatus)Enum.Parse(typeof(SiloStatus), tableEntry.Status!)
};
if (!string.IsNullOrEmpty(tableEntry.ProxyPort))View on GitHub (pinned to fca799fa70)
Solutions
- Recreate the version row: insert an entity with PartitionKey=<deploymentId>, RowKey='Version', MembershipVersion='0' (or the current max), then restart silos.
- If acceptable, delete the whole partition and let Orleans reinitialize the membership table.
- Upgrade all silos to a consistent Orleans version so version-row creation logic agrees.
- Audit cleanup/management code for any path that could delete the version row.
Example fix
// via Azure Data Table SDK
var versionRow = new TableEntity(deploymentId, "Version") {
["MembershipVersion"] = "0"
};
await tableClient.UpsertEntityAsync(versionRow); Defensive patterns
Strategy: try-catch
Validate before calling
// after reading entries, verify a version row exists before consuming:
bool hasVersion = entries.Any(e => e.Entity.RowKey == "Version");
if (!hasVersion) throw new InvalidOperationException("Recreate the Version row."); Try / catch
try { var data = await membershipTable.ReadMembershipTableAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not contain a version row"))
{ /* recreate Version row with MembershipVersion=0 and retry */ } Prevention
- Audit cleanup/migration code so it never deletes the Version row.
- Keep all silos on the same Orleans version.
- If the table is corrupt, delete the partition and reinitialize rather than patching.
When it happens
Trigger: Reading membership when the partition contains silo rows but no TABLE_VERSION_ROW. Happens if the version row was manually removed, a cleanup deleted it, or table initialization failed partway.
Common situations: Manual deletion of the version row in Azure Storage Explorer; a buggy cleanup agent that removed boundary/version rows; partial init where silos registered but the version row insert failed; schema drift between Orleans versions.
Related errors
- The table version row does not contain a membership version.
- SuspectingSilos.Length of {0} as read from Azure table is no
- Did not read table version row. Read = {0}
- The table version entry must have a membership version.
- Value cannot be null. (Parameter 'clusterId')
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/3da05fa5913107e5.
Report an issue: GitHub.