dotnet/orleans · error · OrleansConfigurationException

Invalid {nameof(AdoNetGrainStorageOptions)} values for {name

Error message

Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} "{name}". {nameof(options.Invariant)} is required.

What it means

Thrown by the AdoNetGrainStorageOptionsValidator when Invariant is null or whitespace. AdoNetGrainStorageOptions.Invariant defaults to SQL Server, so this only fires if the default was explicitly cleared to empty or the options object was constructed/serialized without populating Invariant.

Source

Thrown at src/AdoNet/Orleans.Persistence.AdoNet/Options/AdoNetGrainStorageOptions.cs:97

        private readonly string name;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="configurationOptions">The option to be validated.</param>
        /// <param name="name">The name of the option to be validated.</param>
        public AdoNetGrainStorageOptionsValidator(AdoNetGrainStorageOptions configurationOptions, string name)
        {
            this.options = configurationOptions ?? throw new OrleansConfigurationException($"Invalid AdoNetGrainStorageOptions for AdoNetGrainStorage {name}. Options is required.");
            this.name = name;
        }

        /// <inheritdoc cref="IConfigurationValidator"/>
        public void ValidateConfiguration()
        {
            if (string.IsNullOrWhiteSpace(this.options.Invariant))
            {
                throw new OrleansConfigurationException($"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \"{name}\". {nameof(options.Invariant)} is required.");
            }

            if (string.IsNullOrWhiteSpace(this.options.ConnectionString) == (this.options.DataSource is null))
            {
                throw new OrleansConfigurationException($"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \"{name}\". Configure exactly one of {nameof(options.ConnectionString)} or {nameof(options.DataSource)}.");
            }

            if (this.options.HashPicker == null)
            {
                throw new OrleansConfigurationException($"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} {name}. {nameof(options.HashPicker)} is required.");
            }
        }
    }

    /// <summary>
    /// Provides default configuration HashPicker for AdoNetGrainStorageOptions.
    /// </summary>
    public class DefaultAdoNetGrainStorageOptionsHashPickerConfigurator : IPostConfigureOptions<AdoNetGrainStorageOptions>

View on GitHub (pinned to fca799fa70)

Solutions

  1. Remove any empty "Invariant" override in configuration so the SQL Server default applies.
  2. Set options.Invariant = AdoNetInvariants.InvariantNameSqlServer (or PostgreSql/MySql as needed) explicitly.
  3. Bind options with a binder that preserves defaults rather than overwriting with null.

Example fix

// before
// appsettings.json: "Invariant": ""  (wipes default)

// after
// appsettings.json: omit Invariant, or:
"Invariant": "System.Data.SqlClient"
Defensive patterns

Strategy: validation

Validate before calling

static void CheckStorageInvariant(AdoNetGrainStorageOptions o)
{
    if (string.IsNullOrWhiteSpace(o.Invariant))
        throw new InvalidOperationException("AdoNetGrainStorageOptions.Invariant must not be blank.");
}

Prevention

When it happens

Trigger: ValidateConfiguration() runs with options.Invariant explicitly set to "" or null, overriding the DEFAULT_ADONET_INVARIANT (SqlServer) default. Also possible if options are deserialized from config that has an empty Invariant key overriding the default.

Common situations: An appsettings.json "Invariant": "" entry that wipes the default; deserializing options from a source missing the Invariant field with a null-coercing binder; explicitly setting Invariant = null in code.

Related errors


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