DapperLib/Dapper · error · NotSupportedException

The member {name} of type {type.FullName} cannot be used as

Error message

The member {name} of type {type.FullName} cannot be used as a parameter value

What it means

LookupDbType(type, name, demand, out handler) at SqlMapper.cs:461 walks Dapper's typeMap, registered type handlers, and special-case SQL Server UDTs (SqlGeography/SqlGeometry/SqlHierarchyId). If none match and demand is true, it throws NotSupportedException naming the member and its type (SqlMapper.cs:530). This is Dapper saying it has no idea how to turn the member into a parameter value.

Source

Thrown at Dapper/SqlMapper.cs:530

                }
                return DynamicParameters.EnumerableMultiParameter;
            }

            switch (type.FullName)
            {
                case "Microsoft.SqlServer.Types.SqlGeography":
                    AddTypeHandler(type, handler = new UdtTypeHandler("geography"));
                    return DbType.Object;
                case "Microsoft.SqlServer.Types.SqlGeometry":
                    AddTypeHandler(type, handler = new UdtTypeHandler("geometry"));
                    return DbType.Object;
                case "Microsoft.SqlServer.Types.SqlHierarchyId":
                    AddTypeHandler(type, handler = new UdtTypeHandler("hierarchyid"));
                    return DbType.Object;
            }

            if (demand)
                throw new NotSupportedException($"The member {name} of type {type.FullName} cannot be used as a parameter value");
            return DbType.Object;
        }

        /// <summary>
        /// Obtains the data as a list; if it is *already* a list, the original object is returned without
        /// any duplication; otherwise, ToList() is invoked.
        /// </summary>
        /// <typeparam name="T">The type of element in the list.</typeparam>
        /// <param name="source">The enumerable to return as a list.</param>
        public static List<T> AsList<T>(this IEnumerable<T>? source) => source switch
        {
            null => null!,
            List<T> list => list,
            _ => Enumerable.ToList(source),
        };

        /// <summary>
        /// Execute parameterized SQL.

View on GitHub (pinned to 72a54c475f)

Solutions

  1. Register an ITypeHandler via SqlMapper.AddTypeHandler(type, handler) for the offending type.
  2. Project the parameter to a primitive Dapper understands before passing (e.g. myDomain.Value).
  3. Implement ICustomQueryParameter on the type so Dapper can build the DbParameter directly.
  4. For enums, ensure the underlying type is mapped or enable Settings.PreferTypeHandlersForEnums with a handler.

Example fix

// before
public readonly struct Money { public decimal Amount; public string Currency; }
cnn.Execute("insert orders(amount) values(@amount)", new { amount = new Money(10, "USD") }); // throws

// after — flatten to a primitive
cnn.Execute("insert orders(amount) values(@amount)", new { amount = money.Amount });
// or register a handler:
SqlMapper.AddTypeHandler(typeof(Money), new MoneyTypeHandler());
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: ensure every parameter member type is mappable or has a handler
foreach (var p in param.GetType().GetProperties())
{
    var t = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType;
    if (!SqlMapper.HasTypeHandler(t) && !IsPrimitiveMappable(t))
        throw new NotSupportedException($"Register a type handler for {t.FullName} before using it as a parameter");
}

Type guard

static bool IsPrimitiveMappable(Type t) =>
    t.IsPrimitive || t.IsEnum || t == typeof(string) || t == typeof(decimal)
    || t == typeof(DateTime) || t == typeof(Guid) || t == typeof(byte[]);

Try / catch

try { cnn.Execute(sql, param); }
catch (NotSupportedException ex) when (ex.Message.Contains("cannot be used as a parameter value"))
{ /* register handler or project the member to a primitive, then retry */ }

Prevention

When it happens

Trigger: Pass an anonymous object / POCO parameter whose property is a type Dapper cannot map: a complex class, an unregistered struct, an interface, or a custom type with no ITypeHandler. Parameter materialization calls LookupDbType with demand=true for each member.

Common situations: Custom value types or domain objects used as parameters without registering a type handler; passing a navigation property / nested entity object as a param; enums whose underlying type is not in the map; third-party types (e.g. NodaTime, System.Text.Json elements) without a handler.

Related errors


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