dotnet/orleans · error · ArgumentException

{nameof(options.DeleteStateOnClear)}=true is not supported.

Error message

{nameof(options.DeleteStateOnClear)}=true is not supported. Use {nameof(options.DeleteStateOnClear)}=false instead or check persistence scripts.

What it means

Thrown at runtime during ADO.NET grain storage initialization when DeleteStateOnClear is true but the loaded persistence scripts contain no DeleteStorageKey query. It is a backward-compatibility guard: some ADO.NET invariants or deployed script sets do not support delete-on-clear, so Orleans refuses to start rather than silently skipping deletes.

Source

Thrown at src/AdoNet/Orleans.Persistence.AdoNet/Storage/Provider/AdoNetGrainStorage.cs:348

            LogTraceWroteGrainState(serviceId, name, baseGrainType, grainId, grainState.ETag);
        }

        /// <summary> Initialization function for this storage provider. </summary>
        private async Task Init(CancellationToken cancellationToken)
        {
            Storage = RelationalStorage.CreateInstance(options.Invariant, options.ConnectionString, options.DataSource);
            var queries = await Storage.ReadAsync(DefaultInitializationQuery, command => { }, (selector, resultSetCount, token) =>
            {
                return Task.FromResult(Tuple.Create(selector.GetValue<string>("QueryKey"), selector.GetValue<string>("QueryText")));
            }).ConfigureAwait(false);

            // This check is for backward compatibility:
            // 1. Some AdoNet storage invariants may not support delete on clear.
            // 2. AdoNet invariant supports delete on clear but updated persistence scripts have not been deployed to management db.
            var deleteStateQuery = queries.SingleOrDefault(i => i.Item1 == "DeleteStorageKey")?.Item2;
            if (options.DeleteStateOnClear && deleteStateQuery is null)
            {
                throw new ArgumentException($"{nameof(options.DeleteStateOnClear)}=true is not supported. Use {nameof(options.DeleteStateOnClear)}=false instead or check persistence scripts.");
            }
            CurrentOperationalQueries = new RelationalStorageProviderQueries(
                queries.Single(i => i.Item1 == "WriteToStorageKey").Item2,
                queries.Single(i => i.Item1 == "ReadFromStorageKey").Item2,
                queries.Single(i => i.Item1 == "ClearStorageKey").Item2,
                deleteStateQuery);

            LogInfoInitializedStorageProvider(
                serviceId,
                name,
                Storage.InvariantName,
                new(Storage.ConnectionString));
        }

        /// <summary>
        /// Close this provider
        /// </summary>
        private Task Close(CancellationToken token)

View on GitHub (pinned to fca799fa70)

Solutions

  1. Deploy/re-run the current Orleans persistence scripts (e.g. SQLServer-Persistence.sql) so the DeleteStorageKey query row exists.
  2. Set options.DeleteStateOnClear = false to keep clear-as-blank behavior without deleting the row.
  3. Verify the management database's QueryKey rows include DeleteStorageKey after script deployment.

Example fix

// before
builder.AddAdoNetGrainStorage("profile", o =>
{
    o.DeleteStateOnClear = true; // scripts lack DeleteStorageKey -> error at init
});

// after (option A: deploy scripts, option B: disable)
builder.AddAdoNetGrainStorage("profile", o =>
{
    o.DeleteStateOnClear = false;
});
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling DeleteStateOnClear, confirm the scripts include the query.
var hasDelete = await QueriesContainKeyAsync(storage, "DeleteStorageKey");
if (options.DeleteStateOnClear && !hasDelete)
    throw new InvalidOperationException("Deploy persistence scripts with DeleteStorageKey before enabling DeleteStateOnClear.");

Try / catch

try { await grainStorage.Init(); }
catch (ArgumentException ex) when (ex.Message.Contains("DeleteStateOnClear"))
{
    // deploy scripts or disable DeleteStateOnClear, then restart.
}

Prevention

When it happens

Trigger: AdoNetGrainStorage reads the initialization queries from the database (DefaultInitializationQuery) during Init; if options.DeleteStateOnClear == true and no row with QueryKey == "DeleteStorageKey" is present, it throws ArgumentException at init stage.

Common situations: Enabling DeleteStateOnClear on a database whose Orleans persistence scripts are from an older version that predates the DeleteStorageKey script; deploying SQL Server scripts but pointing at a database only initialized for an older schema; partial script deployment.

Related errors


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