dotnet/orleans · error · AggregateException

Unable to convert from storage format GrainStateEntity.Data=

Error message

Unable to convert from storage format GrainStateEntity.Data={0}

What it means

Thrown by ConvertFromStorageFormat when deserialization of stored grain state fails. The method reads binary Data and/or string StringData columns from the TableEntity, constructs a BinaryData input, and attempts to deserialize it to type T. If deserialization throws, the exception is wrapped with diagnostic info (Data, StringData, data type) into an AggregateException.

Source

Thrown at src/Azure/Orleans.Persistence.AzureStorage/Providers/Storage/AzureTableStorage.cs:355

            catch (Exception exc)
            {
                var sb = new StringBuilder();
                if (binaryData.Length > 0)
                {
                    sb.AppendFormat("Unable to convert from storage format GrainStateEntity.Data={0}", binaryData);
                }
                else if (!string.IsNullOrEmpty(stringData))
                {
                    sb.AppendFormat("Unable to convert from storage format GrainStateEntity.StringData={0}", stringData);
                }

                if (dataValue != null)
                {
                    sb.AppendFormat("Data Value={0} Type={1}", dataValue, dataValue.GetType());
                }

                LogErrorSimpleMessage(sb, exc);
                throw new AggregateException(sb.ToString(), exc);
            }

            return dataValue;
        }

        private string GetKeyString(GrainId grainId)
        {
            var key = $"{clusterOptions.ServiceId}_{grainId}";
            return AzureTableUtils.SanitizeTableProperty(key);
        }

        private partial class GrainStateTableDataManager
        {
            public string TableName { get; private set; }
            private readonly AzureTableDataManager<TableEntity> tableManager;
            private readonly ILogger logger;

            public GrainStateTableDataManager(AzureStorageOperationOptions options, ILogger logger)

View on GitHub (pinned to fca799fa70)

Solutions

  1. Ensure backward-compatible grain state changes — use [OrleansConstructor] and optional fields, or implement IOnDeserialized for migration.
  2. Keep the same GrainStorageSerializer configuration across deployments.
  3. Use a custom IGrainStorageSerializer that handles versioning and migration of old formats.
  4. If the data is irrecoverable, delete the stale table entity so the grain starts fresh (data loss).

Example fix

// before: breaking schema change
public class MyGrainState { public int Count; }
// changed to:
public class MyGrainState { public int Total; } // deserialization of old data fails

// after: keep old field and add migration
public class MyGrainState
{
    public int Count; // keep for backward compat
    public int Total;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deploying a schema change, test deserialization against a sample of existing data
var testData = File.ReadAllBytes("sample-entity.bin");
try { var result = storageSerializer.Deserialize<MyGrainState>(new BinaryData(testData)); }
catch (Exception ex) { logger.LogError(ex, "Deserialization will fail for existing data — add migration."); }

Try / catch

try { await grain.ReadStateAsync(); }
catch (AggregateException ex) when (ex.Message.Contains("Unable to convert from storage format"))
{
    logger.LogError(ex, "Stored grain state cannot be deserialized — schema or serializer mismatch.");
    // Consider deleting the stale entity and re-initializing if data loss is acceptable
    throw;
}

Prevention

When it happens

Trigger: A grain's persisted state in Azure Table was serialized with a different serializer or schema than what the current grain type expects. This happens when the grain state class T changed shape (fields renamed/removed), the storage serializer was changed (e.g., from JSON to binary), or the data was written by a different version of the application.

Common situations: Deploying a new version of the grain class with incompatible state schema. Changing the configured GrainStorageSerializer without migrating existing data. Corrupted data in the table. Migrating from one serialization format to another. Version skew during rolling deployments.

Related errors


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