dotnet/orleans · error · OrleansException

Read a reminder entry for wrong Service id. Read {tableEntry

Error message

Read a reminder entry for wrong Service id. Read {tableEntry}, but my service id is {serviceIdStr}. Going to discard it.

What it means

Thrown by AzureBasedReminderTable when a reminder entry read from Azure Table Storage has a ServiceId that does not match the current silo's cluster ServiceId. Each Orleans cluster has a unique ServiceId (from ClusterOptions); reminder entries are scoped to that ServiceId. Reading a reminder from a different service indicates data contamination or a configuration mismatch, and the entry is discarded.

Source

Thrown at src/Azure/Orleans.Reminders.AzureStorage/Storage/AzureBasedReminderTable.cs:122

                    GrainId = GrainId.Parse(tableEntry.GrainReference!),
                    ReminderName = tableEntry.ReminderName!,
                    StartAt = LogFormatter.ParseDate(tableEntry.StartAt!),
                    Period = TimeSpan.Parse(tableEntry.Period!),
                    ETag = eTag,
                };
            }
            catch (Exception exc)
            {
                LogErrorParsingReminderEntry(exc, tableEntry);
                throw;
            }
            finally
            {
                string serviceIdStr = this.clusterOptions.ServiceId;
                if (!tableEntry.ServiceId!.Equals(serviceIdStr))
                {
                    LogWarningAzureTable_ReadWrongReminder(tableEntry, serviceIdStr);
                    throw new OrleansException($"Read a reminder entry for wrong Service id. Read {tableEntry}, but my service id is {serviceIdStr}. Going to discard it.");
                }
            }
        }

        private static ReminderTableEntry ConvertToTableEntry(ReminderEntry remEntry, string serviceId, string deploymentId)
        {
            string partitionKey = ReminderTableEntry.ConstructPartitionKey(serviceId, remEntry.GrainId);
            string rowKey = ReminderTableEntry.ConstructRowKey(remEntry.GrainId, remEntry.ReminderName);

            var consistentHash = remEntry.GrainId.GetUniformHashCode();

            return new ReminderTableEntry
            {
                PartitionKey = partitionKey,
                RowKey = rowKey,

                ServiceId = serviceId,
                DeploymentId = deploymentId,

View on GitHub (pinned to fca799fa70)

Solutions

  1. Ensure ClusterOptions.ServiceId is stable and unique per logical service across deployments — do not change it between restarts.
  2. If the ServiceId was intentionally changed, clean up old reminder entries from the Azure Table or use a different table.
  3. Use separate Azure Storage accounts or table names per cluster/environment to avoid cross-contamination.
  4. Audit the Azure Table for entries with mismatched ServiceId values and delete stale rows.

Example fix

// before: ServiceId changed between deployments
builder.Configure<ClusterOptions>(o => o.ServiceId = Guid.NewGuid().ToString()); // new each run!

// after: stable ServiceId
builder.Configure<ClusterOptions>(o =>
{
    o.ServiceId = "my-service-prod"; // stable across restarts
    o.ClusterId = "cluster-1";
});
Defensive patterns

Strategy: validation

Validate before calling

// Verify ServiceId is stable before starting the silo
var serviceId = configuration["Orleans:ClusterOptions:ServiceId"];
if (string.IsNullOrWhiteSpace(serviceId) || serviceId == Guid.NewGuid().ToString())
    throw new InvalidOperationException("ClusterOptions.ServiceId must be a stable, unique value — do not randomize it.");

Try / catch

try { await reminderTable.ReadRows(begin, end); }
catch (OrleansException ex) when (ex.Message.Contains("wrong Service id"))
{
    logger.LogCritical(ex, "Reminder table contains entries from a different ServiceId — clean up the table or fix the ServiceId.");
    throw;
}

Prevention

When it happens

Trigger: During ReadRow/ReadRows, after parsing a ReminderTableEntry from the table, the finally block checks tableEntry.ServiceId against clusterOptions.ServiceId. If they differ, it throws OrleansException. This can happen if the Azure Table contains reminder data from a different cluster or if the ServiceId changed between deployments.

Common situations: ServiceId in ClusterOptions changed between deployments but the same Azure Table is reused — old reminders from the previous ServiceId are still present. Two clusters accidentally pointed at the same Azure Storage account/table. Copy-paste of config that overwrote the ServiceId. Environment promotion without updating the ServiceId.

Related errors


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