DapperLib/Dapper · error · ApplicationException

Attempting to cast a DBNull to a non nullable type! Note tha

Error message

Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)

What it means

DynamicParameters.Get<T> throws ApplicationException when the output/return parameter value is DBNull.Value and T is a non-nullable value type (default(T) is not null). The library cannot return a null for a value type and refuses to silently coerce DBNull into a default. The message also warns that out/return values are not populated until the data stream completes (after the unbuffered Query foreach, or after the GridReader is disposed for QueryMultiple).

Source

Thrown at Dapper/DynamicParameters.cs:315

        /// </summary>
        public IEnumerable<string> ParameterNames => parameters.Select(p => p.Key);

        /// <summary>
        /// Get the value of a parameter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns>The value, note DBNull.Value is not returned, instead the value is returned as null</returns>
        public T Get<T>(string name)
        {
            var paramInfo = parameters[Clean(name)];
            var attachedParam = paramInfo.AttachedParam;
            object? val = attachedParam is null ? paramInfo.Value : attachedParam.Value;
            if (val == DBNull.Value)
            {
                if (default(T) is not null)
                {
                    throw new ApplicationException("Attempting to cast a DBNull to a non nullable type! Note that out/return parameters will not have updated values until the data stream completes (after the 'foreach' for Query(..., buffered: false), or after the GridReader has been disposed for QueryMultiple)");
                }
                return default!;
            }
            return (T)val!;
        }

        /// <summary>
        /// Allows you to automatically populate a target property/field from output parameters. It actually
        /// creates an InputOutput parameter, so you can still pass data in.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target">The object whose property/field you wish to populate.</param>
        /// <param name="expression">A MemberExpression targeting a property/field of the target (or descendant thereof.)</param>
        /// <param name="dbType"></param>
        /// <param name="size">The size to set on the parameter. Defaults to 0, or DbString.DefaultLength in case of strings.</param>
        /// <returns>The DynamicParameters instance</returns>
        public DynamicParameters Output<T>(T target, Expression<Func<T, object?>> expression, DbType? dbType = null, int? size = null)
        {

View on GitHub (pinned to 72a54c475f)

Solutions

  1. Use a nullable type T (int? / long?) so DBNull maps to null instead of throwing.
  2. Ensure the data stream is fully consumed before reading output parameters (dispose the GridReader, finish the unbuffered foreach).
  3. Coalesce NULL to a default in the SQL procedure (ISNULL/COALESCE) when a non-nullable result is contractually expected.

Example fix

// before
int count = p.Get<int>("@count"); // throws if proc returned NULL

// after
int? count = p.Get<int?>("@count");
int safe = count ?? 0;
Defensive patterns

Strategy: type-guard

Validate before calling

// use nullable T when the output parameter may be NULL
int? count = p.Get<int?>("@count");
int safe = count ?? 0;

Type guard

static bool IsNullableType<T>() => !default(T).GetType().IsValueType || Nullable.GetUnderlyingType(typeof(T)) is not null;

Try / catch

try { return p.Get<T>(name); }
catch (ApplicationException ex) when (ex.Message.Contains("DBNull"))
{ /* T is a non-nullable value type and DB returned NULL — switch to nullable */ }

Prevention

When it happens

Trigger: Calling param.Get<int>("@count") where the procedure returned NULL for that output parameter; reading an output parameter too early (before the unbuffered result stream or GridReader finished); mapping a database NULL to a non-nullable type T.

Common situations: Stored procedure returning NULL on an error/no-rows path bound to int/long/Guid parameters; calling Get<T> inside an unbuffered foreach before the reader finished; mismatch between an always-nullable DB column and a non-nullable CLR type.

Related errors


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