dotnet/orleans · error · ArgumentNullException
Value cannot be null. (Parameter 'selector')
Error message
Value cannot be null. (Parameter 'selector')
What it means
Thrown by RelationalStorage.ReadAsync<TResult> when the selector delegate (Func<IDataRecord, int, CancellationToken, Task<TResult>>) is null. The selector transforms each IDataRecord row into TResult; without it ReadAsync cannot materialize results, so the call is rejected with ArgumentNullException(nameof(selector)). parameterProvider may legitimately be null.
Source
Thrown at src/AdoNet/Shared/Storage/RelationalStorage.cs:202
/// return new Information
/// {
/// TABLE_CATALOG = selector.GetValueOrDefault<string>("TABLE_CATALOG"),
/// TABLE_NAME = selector.GetValueOrDefault<string>("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>
/// <returns>Affected rows count.</returns>
/// <example>This sample shows how to make a hand-tuned database call.
/// <code>
/// //In contract to reading, execute queries are simpler as they return only
/// //the affected rows count if it is available.View on GitHub (pinned to fca799fa70)
Solutions
- Supply a non-null selector, e.g. (record, i, ct) => Task.FromResult(new T { ... }).
- Use the extension ReadAsync<TResult>(storage, query, selector, parameterProvider) or the reflection overload ReadAsync<TResult>(storage, query, parameters) if you want automatic mapping.
- Verify the selector argument is assigned before the call in refactor reviews.
- Enable nullable reference types so a null selector is a compile-time warning.
Example fix
// before
var rows = await storage.ReadAsync<T>(query, null, null); // selector null -> throws
// after
var rows = await storage.ReadAsync<T>(
query,
cmd => {},
(record, i, ct) => Task.FromResult(new T { Id = record.GetValueOrDefault<int>("Id") })); Defensive patterns
Strategy: validation
Validate before calling
if (selector is null) throw new ArgumentNullException(nameof(selector));
Type guard
static bool HasSelector<TResult>(Func<IDataRecord,int,CancellationToken,Task<TResult>>? s) => s is not null;
Try / catch
try { await storage.ReadAsync<T>(query, p, selector); }
catch (ArgumentNullException ex) when (ex.ParamName == nameof(selector)) { /* supply selector */ } Prevention
- Use the reflection-based ReadAsync overload if you want automatic mapping.
- Enable nullable reference types to catch null selectors at compile time.
- Review selectors after signature refactors.
When it happens
Trigger: Calling ReadAsync with a null selector, often by omitting an argument, mis-ordering arguments, or passing a method-group that resolved to null.
Common situations: Refactors that changed the selector signature so the old reference no longer binds; copy-paste that dropped the selector; using the reflection-based ReadAsync overload by mistake.
Related errors
- Invalid offset length
- The name of invariant must contain characters
- Connection string must contain characters
- Configure exactly one of {nameof(connectionString)} or {name
- Value cannot be null. (Parameter 'query')
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/18ef3c354399a646.
Report an issue: GitHub.