dotnet/orleans · error · KeyNotFoundException

Did not read table version row. Read = {0}

Error message

Did not read table version row. Read = {0}

What it means

Thrown by OrleansSiloInstanceManager.FindSiloEntryAndTableVersionRow when the query returned 1-2 rows but none of them is the TABLE_VERSION_ROW. This is distinct from error 154 (no version row at all across the whole partition): here the targeted query came back without a version row, indicating the version row is missing or was not matched. KeyNotFoundException lists what was read.

Source

Thrown at src/Azure/Orleans.Clustering.AzureStorage/OrleansSiloInstanceManager.cs:265

        {
            string rowKey = SiloInstanceTableEntry.ConstructRowKey(siloAddress);

            var filter = TableClient.CreateQueryFilter($"(PartitionKey eq {DeploymentId}) and ((RowKey eq {rowKey}) or (RowKey eq {SiloInstanceTableEntry.TABLE_VERSION_ROW}))");
            var queryResults = await storage.ReadTableEntriesAndEtagsAsync(filter);
            if (queryResults.Count < 1 || queryResults.Count > 2)
                throw new KeyNotFoundException(string.Format("Could not find table version row or found too many entries. Was looking for key {0}, found = {1}", siloAddress, Utils.EnumerableToString(queryResults)));

            var numTableVersionRows = 0;
            foreach (var entry in queryResults)
            {
                if (entry.Item1.RowKey == SiloInstanceTableEntry.TABLE_VERSION_ROW)
                {
                    numTableVersionRows++;
                }
            }

            if (numTableVersionRows < 1)
                throw new KeyNotFoundException(string.Format("Did not read table version row. Read = {0}", Utils.EnumerableToString(queryResults)));

            if (numTableVersionRows > 1)
                throw new KeyNotFoundException(string.Format("Read {0} table version rows, while was expecting only 1. Read = {1}", numTableVersionRows, Utils.EnumerableToString(queryResults)));

            return queryResults;
        }

        internal async Task<List<(SiloInstanceTableEntry Entity, string ETag)>> FindAllSiloEntries(
            CancellationToken cancellationToken = default)
        {
            MembershipTableQueryResult query = default;
            for (var attempt = 0; attempt < MaxMembershipSnapshotAttempts; attempt++)
            {
                query = await membershipTableReadStorage.ReadAllTableEntriesForPartitionAsync(DeploymentId, cancellationToken);
                var tableVersion = ValidateAllSiloEntries(query.Entries);
                if (CanAcceptSnapshot(query, tableVersion))
                {
                    return RemoveBoundaryVersionRows(query.Entries);

View on GitHub (pinned to fca799fa70)

Solutions

  1. Recreate the version row (PartitionKey=DeploymentId, RowKey=Version, MembershipVersion=<current>) and retry.
  2. If the cluster is being initialized, ensure CreateTableVersionEntry runs at startup before silos query.
  3. Audit for any cleanup or migration code that could remove the version row.
  4. Run all silos on the same Orleans version so the version-row RowKey is consistent.

Example fix

// remediation
var versionRow = new TableEntity(deploymentId, "Version") { ["MembershipVersion"] = currentVersion.ToString() };
await tableClient.UpsertEntityAsync(versionRow);
// then retry FindSiloEntryAndTableVersionRow
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the version row exists in the partition before targeted silo reads:
var any = await manager.FindAllSiloEntries();
bool hasVersion = any.Any(e => e.Entity.RowKey == SiloInstanceTableEntry.TABLE_VERSION_ROW);
if (!hasVersion) { /* recreate Version row */ }

Try / catch

try { var rows = await manager.FindSiloEntryAndTableVersionRow(addr); }
catch (KeyNotFoundException ex) when (ex.Message.Contains("Did not read table version row"))
{ /* recreate Version row and retry */ }

Prevention

When it happens

Trigger: The silo row was found but the version row was absent from the 1-2 returned entities. Happens when the version row was deleted, not yet created, or the RowKey comparison fails due to casing/encoding.

Common situations: Version row manually removed; partial init where the silo registered before the version row insert; mixed Orleans versions with different version-row RowKey conventions; the partition was migrated and the version row dropped.

Related errors


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