{"record":{"id":"857ea89ec7401b30","repo":"dotnet/orleans","slug":"suspectingsilos-length-of-0-as-read-from-azure-t","errorCode":null,"errorMessage":"SuspectingSilos.Length of {0} as read from Azure table is not equal to SuspectingTimes.Length of {1}","messagePattern":"SuspectingSilos\\.Length of (.+?) as read from Azure table is not equal to SuspectingTimes\\.Length of (.+?)","errorType":"exception","errorClass":"OrleansException","httpStatus":null,"severity":"warning","filePath":"src/Azure/Orleans.Clustering.AzureStorage/AzureBasedMembershipTable.cs","lineNumber":276,"sourceCode":"\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingSilos))\n            {\n                string[] silos = tableEntry.SuspectingSilos.Split('|');\n                foreach (string silo in silos)\n                {\n                    suspectingSilos.Add(SiloAddress.FromParsableString(silo));\n                }\n            }\n\n            if (!string.IsNullOrEmpty(tableEntry.SuspectingTimes))\n            {\n                string[] times = tableEntry.SuspectingTimes.Split('|');\n                foreach (string time in times)\n                    suspectingTimes.Add(LogFormatter.ParseDate(time));\n            }\n\n            if (suspectingSilos.Count != suspectingTimes.Count)\n                throw new OrleansException(string.Format(\"SuspectingSilos.Length of {0} as read from Azure table is not equal to SuspectingTimes.Length of {1}\", suspectingSilos.Count, suspectingTimes.Count));\n\n            for (int i = 0; i < suspectingSilos.Count; i++)\n                parse.AddSuspector(suspectingSilos[i], suspectingTimes[i]);\n\n            return parse;\n        }\n\n        private static SiloInstanceTableEntry Convert(MembershipEntry memEntry, string deploymentId)\n        {\n            var tableEntry = new SiloInstanceTableEntry\n            {\n                DeploymentId = deploymentId,\n                Address = memEntry.SiloAddress.Endpoint.Address.ToString(),\n                Port = memEntry.SiloAddress.Endpoint.Port.ToString(CultureInfo.InvariantCulture),\n                Generation = memEntry.SiloAddress.Generation.ToString(CultureInfo.InvariantCulture),\n                HostName = memEntry.HostName,\n                Status = memEntry.Status.ToString(),\n                ProxyPort = memEntry.ProxyPort.ToString(CultureInfo.InvariantCulture),","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Clustering.AzureStorage/AzureBasedMembershipTable.cs#L258-L294","documentation":"Thrown by AzureBasedMembershipTable.Parse when the SuspectingSilos and SuspectingTimes pipe-delimited lists have different lengths. Membership uses these parallel lists to record which silos voted a peer as suspect and when; a length mismatch indicates a corrupt or partially-written entity. OrleansException (not ArgumentException) is thrown inside Parse and, because Parse is called within the per-entry try, is logged-and-ignored via LogErrorParsingMembershipTableDataIgnoring, so the offending entry is skipped rather than fatal.","triggerScenarios":"A membership table entity has SuspectingSilos with N entries and SuspectingTimes with M != N entries (split on '|'). Occurs when a silo crashed mid-write of those two fields, or when an external tool edited only one field.","commonSituations":"Silo crash between updating SuspectingSilos and SuspectingTimes; manual entity edits; storage serialization that dropped one field; mixed-version cluster writing fields with different separators.","solutions":["Inspect the offending entity's SuspectingSilos and SuspectingTimes fields and reconcile them (trim the longer list to match).","Let the table self-heal: because the entry is skipped, the next membership update will overwrite the suspector lists consistently.","Force a membership refresh (restart a silo or call CleanupDefunctSiloEntries) to re-stamp suspect data.","Avoid manual edits to suspector fields; they are written atomically by Orleans in normal operation."],"exampleFix":"// remediation in Azure Storage Explorer\n// entity RowKey=<silo>: set SuspectingSilos and SuspectingTimes to '' (empty)\n// then let Orleans repopulate them on the next suspicion cycle","handlingStrategy":"try-catch","validationCode":"// validate suspector parallel lists before relying on them:\nint silos = string.IsNullOrEmpty(entry.SuspectingSilos) ? 0 : entry.SuspectingSilos.Split('|').Length;\nint times = string.IsNullOrEmpty(entry.SuspectingTimes) ? 0 : entry.SuspectingTimes.Split('|').Length;\nif (silos != times) { /* skip or repair entry */ }","typeGuard":null,"tryCatchPattern":"// Parse swallows this via LogErrorParsingMembershipTableDataIgnoring, so the entry is skipped.\n// To detect: subscribe to the LogErrorParsingMembershipTableDataIgnoring log event and alert on it.","preventionTips":["Let Orleans repopulate suspector fields by triggering a membership refresh.","Avoid manual edits to SuspectingSilos/SuspectingTimes.","Monitor the 'error parsing membership table data, ignoring' log for early detection."],"tags":["csharp","dotnet","orleans","azure-storage","membership","data-corruption"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}