tursodatabase/turso · error · InvalidCastException
Cannot convert remote {Type} value to Decimal.
Error message
Cannot convert remote {Type} value to Decimal. What it means
GetDecimal on a reader column whose remote value type is not float, integer, or text. The remote protocol has no decimal type -- floats and text are converted -- but NULL and BLOB have no arm, so those cells throw InvalidCastException from the typed getter.
Source
Thrown at bindings/dotnet/src/Turso.Data/TursoRemoteClient.cs:698
public double GetDouble()
{
return Type switch
{
"float" => ParseFloat(),
"integer" => ParseInteger(),
"text" => double.Parse(Value.GetString() ?? "", CultureInfo.InvariantCulture),
_ => throw new InvalidCastException($"Cannot convert remote {Type} value to Double."),
};
}
public decimal GetDecimal()
{
return Type switch
{
"float" => Convert.ToDecimal(ParseFloat(), CultureInfo.InvariantCulture),
"integer" => ParseInteger(),
"text" => decimal.Parse(Value.GetString() ?? "", CultureInfo.InvariantCulture),
_ => throw new InvalidCastException($"Cannot convert remote {Type} value to Decimal."),
};
}
private long ParseInteger()
{
return Value.ValueKind == JsonValueKind.String
? long.Parse(Value.GetString() ?? "", CultureInfo.InvariantCulture)
: Value.GetInt64();
}
private double ParseFloat()
{
return Value.ValueKind == JsonValueKind.String
? double.Parse(Value.GetString() ?? "", CultureInfo.InvariantCulture)
: Value.GetDouble();
}
private static byte[] DecodeBase64(string value)View on GitHub (pinned to 6c72522679)
Solutions
- Guard with reader.IsDBNull(i) before GetDecimal and choose a default (0m or throwing a domain-specific error).
- Use COALESCE(col, 0) in SQL when a zero default is acceptable.
- Prefer storing money as integer minor units or TEXT and converting explicitly, since the wire protocol has no exact decimal type.
- Verify the column ordinal and declared type before using typed getters.
Example fix
// before decimal total = reader.GetDecimal(2); // after decimal total = reader.IsDBNull(2) ? 0m : reader.GetDecimal(2);
Defensive patterns
Strategy: validation
Validate before calling
if (reader.IsDBNull(ordinal))
return 0m;
return reader.GetDecimal(ordinal); Type guard
static bool CanReadDecimal(System.Data.Common.DbDataReader reader, int i) =>
!reader.IsDBNull(i)
&& reader.GetFieldType(i) is Type t
&& (t == typeof(decimal) || t == typeof(double) || t == typeof(long) || t == typeof(string)); Try / catch
try { value = reader.GetDecimal(i); }
catch (InvalidCastException) when (reader.IsDBNull(i))
{
value = 0m; // explicit policy for NULL money columns
} Prevention
- Store money as integer minor units or well-formed TEXT, since the wire protocol has no exact decimal type.
- Wrap nullable amount columns in COALESCE at the query level when zero is a sane default.
- Check IsDBNull before every GetDecimal on nullable columns.
- Culture-proof text-to-decimal parsing: the binding parses invariantly, so store canonical formats.
When it happens
Trigger: reader.GetDecimal(i) on a remote connection where column i is NULL, a BLOB, or an unsupported type; text cells are parsed with decimal.Parse and throw FormatException for non-numeric or culture-incompatible strings.
Common situations: Money/amount columns stored as REAL or TEXT and occasionally NULL; LEFT JOIN or outer-aggregate queries producing NULL cells; schema changes after deployment.
Related errors
- Cannot convert remote {Type} value to Int64.
- Cannot convert remote {Type} value to Double.
- Remote response returned unsupported value type: {Type}
- Embedded replica sync is not supported yet by the .NET provi
- Embedded replica connections are not supported yet by the .N
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/a11653ca99481da7.
Report an issue: GitHub.