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
- Use a nullable type T (int? / long?) so DBNull maps to null instead of throwing.
- Ensure the data stream is fully consumed before reading output parameters (dispose the GridReader, finish the unbuffered foreach).
- 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
- Bind nullable DB columns to nullable CLR types (int?, DateTime?).
- For unbuffered/QueryMultiple, dispose the reader / finish iterating before reading output params.
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.