dotnet/orleans · error · ArgumentNullException

Value cannot be null. (Parameter 'query')

Error message

Value cannot be null. (Parameter 'query')

What it means

Thrown by RelationalStorage.ReadAsync<TResult>(string query, ...) when query is null. The method deliberately allows empty strings (the database will surface its own error) but rejects null outright with ArgumentNullException(nameof(query)). The selector, not the query text, is the only other hard prerequisite.

Source

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

        ///     //marked with by convention by underscore (_).
        /// }, (selector, resultSetCount) =>
        ///    {
        ///        //This function is called once for each row returned, so the final result will be an
        ///        //IEnumerable&lt;Information&gt;.
        ///        return new Information
        ///        {
        ///            TABLE_CATALOG = selector.GetValueOrDefault&lt;string&gt;("TABLE_CATALOG"),
        ///            TABLE_NAME = selector.GetValueOrDefault&lt;string&gt;("TABLE_NAME")
        ///        }
        ///}).ConfigureAwait(continueOnCapturedContext: false);
        /// </code>
        /// </example>
        public async Task<IEnumerable<TResult>> ReadAsync<TResult>(string query, Action<IDbCommand>? parameterProvider, Func<IDataRecord, int, CancellationToken, Task<TResult>> selector, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default)
        {
            //If the query is something else that is not acceptable (e.g. an empty string), there will an appropriate database exception.
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }

            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            return (await ExecuteAsync(query, parameterProvider, ExecuteReaderAsync, selector, commandBehavior, cancellationToken).ConfigureAwait(false)).Item1;
        }


        /// <summary>
        /// Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.
        /// </summary>
        /// <param name="query">The query to execute.</param>
        /// <param name="parameterProvider">Adds parameters to the query. Parameter names must match those defined in the query.</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>

View on GitHub (pinned to fca799fa70)

Solutions

  1. Pass a non-null SQL string; build queries with a builder that never returns null (use string.Empty to let the DB reject it, or validate first).
  2. Load SQL scripts defensively: var sql = await File.ReadAllTextAsync(path); and check for null/empty before calling ReadAsync.
  3. Coalesce nulls: query ?? throw new ArgumentNullException(nameof(query)).
  4. Unit-test query providers to guarantee non-null output.

Example fix

// before
var rows = await storage.ReadAsync<T>(queryOrNull, p, selector);

// after
if (queryOrNull is null) throw new InvalidOperationException("Query not loaded.");
var rows = await storage.ReadAsync<T>(queryOrNull, p, selector);
Defensive patterns

Strategy: validation

Validate before calling

if (query is null) throw new ArgumentNullException(nameof(query));

Type guard

static bool HasQuery(string? q) => q is not null;

Try / catch

try { await storage.ReadAsync<T>(query, p, selector); }
catch (ArgumentNullException ex) when (ex.ParamName == nameof(query)) { /* load script */ }

Prevention

When it happens

Trigger: Calling storage.ReadAsync<TResult>(null, parameterProvider, selector, ...) where the query string was not supplied, e.g. a query-builder returned null or a field was not loaded from a script file.

Common situations: See trigger scenarios.

Related errors


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