tursodatabase/turso · error · InvalidCastException
Cannot convert remote {value.Type} value to DateTime.
Error message
Cannot convert remote {value.Type} value to DateTime. What it means
TursoRemoteDataReader.GetDateTime only accepts values whose remote (Hrana) wire type is exactly "text", which it parses with DateTime.Parse using the invariant culture. Any other wire type (integer, float, blob, null) throws InvalidCastException naming the type. SQLite has no DateTime storage class, so dates must travel as ISO-8601 text for this getter to work.
Source
Thrown at bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs:101
EnsureOpen();
ValidateOrdinal(ordinal);
var declaredType = ordinal < CurrentResult.Columns.Count
? CurrentResult.Columns[ordinal].DeclType
: null;
if (!string.IsNullOrWhiteSpace(declaredType))
return declaredType;
var value = FirstNonNullValue(ordinal);
return value is null ? string.Empty : GetTypeName(value.Type);
}
public override DateTime GetDateTime(int ordinal)
{
var value = CurrentValue(ordinal);
return value.Type == "text"
? DateTime.Parse((string)value.ToClrValue(), CultureInfo.InvariantCulture)
: throw new InvalidCastException($"Cannot convert remote {value.Type} value to DateTime.");
}
public override decimal GetDecimal(int ordinal)
{
return CurrentValue(ordinal).GetDecimal();
}
public override double GetDouble(int ordinal)
{
return CurrentValue(ordinal).GetDouble();
}
public override Type GetFieldType(int ordinal)
{
EnsureOpen();
ValidateOrdinal(ordinal);
if (ordinal < CurrentResult.Columns.CountView on GitHub (pinned to 6c72522679)
Solutions
- Store and select dates as ISO-8601 TEXT (e.g. datetime('iso8601') / parameterize DateTime values, which bind as text) so the wire type is text.
- If the column is numeric, read it with GetValue/GetInt64 and convert manually (DateTimeOffset.FromUnixTimeSeconds for epoch values, or the Julian-day formula for REAL).
- Guard with IsDBNull(ordinal) before calling GetDateTime to handle NULL timestamps separately.
- Inspect reader.GetDataTypeName(ordinal) or GetFieldType(ordinal) per row when the schema is not under your control, and branch on the reported type.
Example fix
// before
DateTime created = reader.GetDateTime(2); // column holds unix-epoch integer -> InvalidCastException
// after
object raw = reader.GetValue(2);
DateTime created = raw switch
{
string s => DateTime.Parse(s, CultureInfo.InvariantCulture),
long epoch => DateTimeOffset.FromUnixTimeSeconds(epoch).UtcDateTime,
DBNull => throw new InvalidOperationException("created must not be null"),
_ => throw new InvalidCastException()
}; Defensive patterns
Strategy: validation
Validate before calling
// before GetDateTime: confirm the cell is text and not null
bool CanGetDateTime(DbDataReader reader, int ordinal) =>
!reader.IsDBNull(ordinal) && reader.GetDataTypeName(ordinal) == "TEXT"; Type guard
static bool IsTextColumn(DbDataReader r, int ord) => r.GetDataTypeName(ord).Equals("TEXT", StringComparison.OrdinalIgnoreCase); Try / catch
try { var dt = reader.GetDateTime(i); }
catch (InvalidCastException) { var raw = reader.GetValue(i); /* convert epoch/Julian manually */ } Prevention
- Store dates as ISO-8601 TEXT so the Hrana wire type is always text.
- Decide on one date encoding per column and enforce it with CHECK constraints or insert-side conversions.
- Check IsDBNull before every nullable date read.
When it happens
Trigger: Calling reader.GetDateTime(ordinal) on a column whose current value is not text: a unix-epoch INTEGER produced by strftime('%s',...), a Julian-day REAL, a blob, or NULL. The type check is on the per-cell wire type, so even a declared TEXT column throws if the stored value for that row is numeric.
Common situations: A table written by another app or language that stores dates as unix epoch integers or REAL Julian day numbers; migrating schema from a server database that used native date types; NULL timestamps on optional columns; EF or Dapper materializers that map DateTime without a value converter.
Related errors
- Turso batch execution is currently supported only for remote
- SqliteBlob requires an open connection.
- TursoBatchCommand only supports CommandType.Text.
- Batch command must be a TursoBatchCommand.
- TursoCommand only supports CommandType.Text.
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/3251791f0331e64c.
Report an issue: GitHub.