dotnet/orleans · error · ArgumentException

Configure exactly one of {nameof(connectionString)} or {name

Error message

Configure exactly one of {nameof(connectionString)} or {nameof(dataSource)}.

What it means

Thrown by the 3-argument RelationalStorage.CreateInstance(string invariantName, string? connectionString, DbDataSource? dataSource) when the (connectionString, dataSource) pair is ambiguous: both null/whitespace or both set. The contract is 'exactly one' connection source so storage does not silently pick a winner. Note the message uses nameof tokens literally inside an interpolated string, so it reads with the literal C# syntax unless rewritten.

Source

Thrown at src/AdoNet/Shared/Storage/RelationalStorage.cs:134

        {
            if (string.IsNullOrWhiteSpace(invariantName))
            {
                throw new ArgumentException("The name of invariant must contain characters", nameof(invariantName));
            }

            ArgumentNullException.ThrowIfNull(dataSource);
            DbConnectionFactory.ValidateDataSource(invariantName, dataSource);
            return new RelationalStorage(invariantName, dataSource);
        }

        /// <summary>
        /// Creates an instance using exactly one configured connection source.
        /// </summary>
        public static IRelationalStorage CreateInstance(string invariantName, string? connectionString, DbDataSource? dataSource)
        {
            if (string.IsNullOrWhiteSpace(connectionString) == (dataSource is null))
            {
                throw new ArgumentException($"Configure exactly one of {nameof(connectionString)} or {nameof(dataSource)}.");
            }

            return dataSource is null
                ? CreateInstance(invariantName, connectionString!)
                : CreateInstance(invariantName, dataSource);
        }


        /// <summary>
        /// Executes a given statement. Especially intended to use with <em>SELECT</em> statement.
        /// </summary>
        /// <typeparam name="TResult">The result type.</typeparam>
        /// <param name="query">Executes a given statement. Especially intended to use with <em>SELECT</em> statement.</param>
        /// <param name="parameterProvider">Adds parameters to the query. Parameter names must match those defined in the query.</param>
        /// <param name="selector">This function transforms the raw <see cref="IDataRecord"/> results to type <see paramref="TResult"/> the <see cref="int"/> parameter being the resultset number.</param>
        /// <param name="commandBehavior">The command behavior that should be used. Defaults to <see cref="CommandBehavior.Default"/>.</param>
        /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param>
        /// <returns>A list of objects as a result of the <see paramref="query"/>.</returns>

View on GitHub (pinned to fca799fa70)

Solutions

  1. Set exactly one of connectionString or dataSource; leave the other null.
  2. Decide your connection strategy upfront: connection-string-based OR DbDataSource-based, and clear the unused option.
  3. Add a configuration validator that rejects options where both are populated or both are empty.
  4. If you only ever use a connection string, call the 2-argument CreateInstance(invariantName, connectionString) overload instead.

Example fix

// before - both set or both null
var storage = RelationalStorage.CreateInstance(invariant, connStr, dataSource); // throws if both/null

// after - exactly one
var storage = RelationalStorage.CreateInstance(invariant, connStr, dataSource: null);
Defensive patterns

Strategy: validation

Validate before calling

bool hasCs = !string.IsNullOrWhiteSpace(connectionString);
bool hasDs = dataSource is not null;
if (hasCs == hasDs)
    throw new InvalidOperationException("Configure exactly one of connectionString or dataSource.");

Type guard

static bool ExactlyOneSource(string? cs, DbDataSource? ds)
    => !string.IsNullOrWhiteSpace(cs) ^ (ds is not null);

Try / catch

try { storage = RelationalStorage.CreateInstance(inv, cs, ds); }
catch (ArgumentException) { /* clear one of the two */ }

Prevention

When it happens

Trigger: Calling the overload with both connectionString and dataSource null, or both non-null. The check is `string.IsNullOrWhiteSpace(connectionString) == (dataSource is null)` which is true when both are missing or both are present.

Common situations: Configuring both a connection string and a data source in options (ambiguous intent); neither configured (defaults to null/null); refactor that left both fields populated; conditional config that sometimes sets both.

Related errors


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