DapperLib/Dapper · error · NotSupportedException
The type '{value.GetType().Name}' is not supported for SQL l
Error message
The type '{value.GetType().Name}' is not supported for SQL literals. What it means
Thrown by `SqlMapper.Format(object?)` when a value used in a literal substitution (`{=name}`) is of a type Dapper will not inline as a SQL literal. Format only inlines numeric primitives (bool, byte/sbyte, ushort/short, uint/int, ulong/long, float, double, decimal) and recursively-formatted enumerables of those; everything else — strings, DateTime, Guid, TimeSpan, char, enums of non-int backing, custom types — falls through to NotSupportedException. This is intentional: inlining strings/dates would risk SQL injection.
Source
Thrown at Dapper/SqlMapper.cs:2504
sb = GetStringBuilder().Append('(');
first = false;
}
else
{
sb!.Append(',');
}
sb.Append(Format(subval));
}
if (first)
{
return "(select null where 1=0)";
}
else
{
return sb!.Append(')').ToStringRecycle();
}
}
throw new NotSupportedException($"The type '{value.GetType().Name}' is not supported for SQL literals.");
}
}
}
internal static void ReplaceLiterals(IParameterLookup parameters, IDbCommand command, IList<LiteralToken> tokens)
{
var sql = command.CommandText;
foreach (var token in tokens)
{
object? value = parameters[token.Member];
#pragma warning disable 0618
string text = Format(value);
#pragma warning restore 0618
sql = sql.Replace(token.Token, text);
}
command.CommandText = sql;
}
View on GitHub (pinned to 72a54c475f)
Solutions
- Use a normal parameter (`@name`) instead of `{=name}` for strings, dates, Guids, and other non-numeric values.
- If you must inline a date/guid, pre-format it to a SQL-safe string literal yourself and only then use it (with extreme care), or keep it parameterized.
- Register a custom literal type handler / convert the value to a supported primitive before substitution.
- Double-check that the literal token points at a numeric column/value.
Example fix
// before (DateTime not supported as literal)
var sql = "select * from t where created = {=AsOf}";
var rows = cnn.Query<T>(sql, new { AsOf = DateTime.UtcNow });
// after
var sql = "select * from t where created = @AsOf";
var rows = cnn.Query<T>(sql, new { AsOf = DateTime.UtcNow }); Defensive patterns
Strategy: validation
Validate before calling
// Only inline numeric literals with {=}; parameterize everything else.
var sql = isNumeric ? $"... {=Value}" : "... @Value"; Type guard
static bool IsLiteralSafe(object? v) => v is bool or byte or sbyte or short or ushort or int or uint or long or ulong or float or double or decimal;
Prevention
- Reserve {=} for numeric values; use @params for strings/dates/guids.
- Never inline strings/dates via literals — SQL injection risk.
- Pre-format unsupported types yourself only if strictly necessary.
When it happens
Trigger: Using the literal syntax `where created = {=Created}` where `Created` is a DateTime, or `where name = {=Name}` where Name is a string; passing a Guid, TimeSpan, or a custom struct to a `{=...}` token. The token is resolved by ReplaceLiterals (SqlMapper.cs:2509) which calls Format on the member value.
Common situations: Confusing literal substitution `{=x}` (safe only for numbers) with normal parameterization `@x`; trying to inline a date or GUID for a provider that needs it inlined; using `{=}` on a string for convenience.
Related errors
- A single-character was expected
- An item with the same key has already been added
- type
- This operation requires an identity or a connected command
- type
AI-assisted analysis of DapperLib/Dapper@72a54c475f (2026-08-13).
Data as JSON: /api/errors/8ed35d9f3a0fd168.
Report an issue: GitHub.