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
- Ensure ClusterOptions.ServiceId is stable and unique per logical service across deployments — do not change it between restarts.
- If the ServiceId was intentionally changed, clean up old reminder entries from the Azure Table or use a different table.
- Use separate Azure Storage accounts or table names per cluster/environment to avoid cross-contamination.
- 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
- Never randomize ClusterOptions.ServiceId — it must be stable across restarts.
- Use separate Azure Storage tables or accounts per environment to avoid reminder contamination.
- When changing ServiceId intentionally, clean up stale reminder entries from the old ServiceId.
- Document the ServiceId in deployment config and audit it during environment promotion.
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
- No credentials specified. Use the {options.GetType().Name}.C
- No credentials specified. Use the AzureBlobStorageOptions.Co
- Configuration for AzureBlobStorageOptions {name} is invalid.
- GrainState-Table property not initialized
- Table storage condition not Satisfied. GrainType: {0}, Grai
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/cc4a3cc4be828a73.
Report an issue: GitHub.