DapperLib/Dapper · error · ArgumentNullException

type

Error message

type

What it means

GridReader.ReadAsync(Type type, bool buffered) is the non-generic async overload that materializes the next result grid into instances of a runtime Type. It throws ArgumentNullException(nameof(type)) at SqlMapper.GridReader.Async.cs:54 when type is null. The generic ReadAsync<T> overloads cannot hit this because typeof(T) is always non-null.

Source

Thrown at Dapper/SqlMapper.GridReader.Async.cs:54

            /// </summary>
            /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
            public Task<dynamic> ReadSingleAsync() => ReadRowAsyncImpl<dynamic>(typeof(DapperRow), Row.Single);

            /// <summary>
            /// Read an individual row of the next grid of results, returned as a dynamic object
            /// </summary>
            /// <remarks>Note: the row can be accessed via "dynamic", or by casting to an IDictionary&lt;string,object&gt;</remarks>
            public Task<dynamic?> ReadSingleOrDefaultAsync() => ReadRowAsyncImpl<dynamic?>(typeof(DapperRow), Row.SingleOrDefault);

            /// <summary>
            /// Read the next grid of results
            /// </summary>
            /// <param name="type">The type to read.</param>
            /// <param name="buffered">Whether to buffer the results.</param>
            /// <exception cref="ArgumentNullException"><paramref name="type"/> is <c>null</c>.</exception>
            public Task<IEnumerable<object>> ReadAsync(Type type, bool buffered = true)
            {
                if (type is null) throw new ArgumentNullException(nameof(type));
                return ReadAsyncImpl<object>(type, buffered);
            }

            /// <summary>
            /// Read an individual row of the next grid of results
            /// </summary>
            /// <param name="type">The type to read.</param>
            /// <exception cref="ArgumentNullException"><paramref name="type"/> is <c>null</c>.</exception>
            public Task<object> ReadFirstAsync(Type type)
            {
                if (type is null) throw new ArgumentNullException(nameof(type));
                return ReadRowAsyncImpl<object>(type, Row.First);
            }

            /// <summary>
            /// Read an individual row of the next grid of results.
            /// </summary>
            /// <param name="type">The type to read.</param>

View on GitHub (pinned to 72a54c475f)

Solutions

  1. Null-check type before the call: if (type is null) throw ...; or fall back to a default type.
  2. Prefer the generic overload ReadAsync<T>() which makes a null type unrepresentable.
  3. Validate the Type source (Type.GetType / Assembly.GetType) for null immediately after resolution and log the failing type name.

Example fix

// before
Type t = Type.GetType(typeName); // null if not found
var rows = await grid.ReadAsync(t);

// after
Type t = Type.GetType(typeName) ?? throw new InvalidOperationException($"Unknown type: {typeName}");
var rows = await grid.ReadAsync(t);
Defensive patterns

Strategy: validation

Validate before calling

if (type is null) throw new InvalidOperationException("type must be resolved before reading a grid");
var rows = await grid.ReadAsync(type);

Type guard

static Type? ResolveType(string name) => Type.GetType(name);
// before use:
Type t = ResolveType(name) ?? throw new InvalidOperationException($"Unresolved type {name}");

Prevention

When it happens

Trigger: Call grid.ReadAsync((Type)null) on a GridReader from QueryMultipleAsync. Typical when the Type comes from a variable, reflection, or a config lookup that resolved to null.

Common situations: Mapping result sets by type loaded via Type.GetType(name) where the name was wrong and returned null; deserialization dispatch tables with a missing entry; runtime polymorphic readers.

Related errors


AI-assisted analysis of DapperLib/Dapper@72a54c475f (2026-08-13). Data as JSON: /api/errors/779ed5a3874c9a4a. Report an issue: GitHub.