{"record":{"id":"8ead0a384ed5a332","repo":"dotnet/orleans","slug":"value-cannot-be-null-parameter-clusterid","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'clusterId')","messagePattern":"Value cannot be null\\. \\(Parameter 'clusterId'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Azure/Orleans.Clustering.AzureStorage/OrleansSiloInstanceManager.cs","lineNumber":208,"sourceCode":"                sb.AppendLine(string.Format(\"[IP {0}:{1}:{2}, {3}, Instance={4}, Status={5}]\", entry.Address, entry.Port, entry.Generation,\n                    entry.HostName, entry.SiloName, entry.Status));\n            }\n            return sb.ToString();\n        }\n\n        internal Task<string> MergeTableEntryAsync(SiloInstanceTableEntry data)\n        {\n            return storage.MergeTableEntryAsync(data, AzureTableUtils.ANY_ETAG); // we merge this without checking eTags.\n        }\n\n        internal Task<(SiloInstanceTableEntry? Entity, string? ETag)> ReadSingleTableEntryAsync(string partitionKey, string rowKey)\n        {\n            return storage.ReadSingleTableEntryAsync(partitionKey, rowKey);\n        }\n\n        internal async Task<int> DeleteTableEntries(string clusterId)\n        {\n            if (clusterId == null) throw new ArgumentNullException(nameof(clusterId));\n\n            var entries = await storage.ReadAllTableEntriesForPartitionAsync(clusterId);\n\n            await DeleteEntriesBatch(entries);\n\n            return entries.Count;\n        }\n\n        public async Task CleanupDefunctSiloEntries(DateTimeOffset beforeDate)\n        {\n            var entriesList = (await FindAllSiloEntries())\n                .Where(entry => !SiloInstanceTableEntry.IsVersionRow(entry.Entity.RowKey)\n                    && entry.Item1.Status != INSTANCE_STATUS_ACTIVE\n                    && entry.Item1.Timestamp < beforeDate)\n                .ToList();\n\n            // Defunct-row cleanup intentionally does not advance the membership snapshot fence.\n            await DeleteEntriesBatch(entriesList);","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Orleans.Clustering.AzureStorage/OrleansSiloInstanceManager.cs#L190-L226","documentation":"Thrown by OrleansSiloInstanceManager.DeleteTableEntries(string clusterId) when clusterId is null. The cluster/deployment id is the Azure Table partition key for membership entries; a null cannot scope the deletion, so the call is rejected with ArgumentNullException(nameof(clusterId)). This is a defensive guard before ReadAllTableEntriesForPartitionAsync.","triggerScenarios":"Calling DeleteTableEntries(null), e.g. an admin/cleanup tool that read the cluster id from a missing config value, or an automated teardown script with an unbound option.","commonSituations":"Cluster teardown tooling with an unbound ClusterId/DeploymentId option; misconfigured test harness; refactor that renamed the option but left the binding stale.","solutions":["Pass the concrete cluster id (the DeploymentId used when the cluster was created).","Bind clusterId from configuration and validate non-null before teardown.","Use `clusterId ?? throw new InvalidOperationException(\"ClusterId not configured.\")` for a clearer upstream error.","Add a startup check that the deployment-id option is set on all silos."],"exampleFix":"// before\nawait manager.DeleteTableEntries(clusterId: null);\n\n// after\nvar cid = options.ClusterId ?? throw new InvalidOperationException(\"ClusterId missing.\");\nawait manager.DeleteTableEntries(cid);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(clusterId))\n    throw new InvalidOperationException(\"ClusterId/DeploymentId is not configured.\");","typeGuard":"static bool HasClusterId(string? s) => !string.IsNullOrWhiteSpace(s);","tryCatchPattern":"try { await manager.DeleteTableEntries(clusterId); }\ncatch (ArgumentNullException ex) when (ex.ParamName == nameof(clusterId)) { /* bind option */ }","preventionTips":["Bind and validate ClusterId/DeploymentId at startup.","Never invoke teardown tools with unbound options.","Coalesce null with a clear upstream error."],"tags":["csharp","dotnet","orleans","azure-storage","membership","argument-validation"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}