{"record":{"id":"3251791f0331e64c","repo":"tursodatabase/turso","slug":"cannot-convert-remote-value-type-value-to-dateti","errorCode":null,"errorMessage":"Cannot convert remote {value.Type} value to DateTime.","messagePattern":"Cannot convert remote (.+?) value to DateTime\\.","errorType":"exception","errorClass":"InvalidCastException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs","lineNumber":101,"sourceCode":"        EnsureOpen();\n        ValidateOrdinal(ordinal);\n\n        var declaredType = ordinal < CurrentResult.Columns.Count\n            ? CurrentResult.Columns[ordinal].DeclType\n            : null;\n        if (!string.IsNullOrWhiteSpace(declaredType))\n            return declaredType;\n\n        var value = FirstNonNullValue(ordinal);\n        return value is null ? string.Empty : GetTypeName(value.Type);\n    }\n\n    public override DateTime GetDateTime(int ordinal)\n    {\n        var value = CurrentValue(ordinal);\n        return value.Type == \"text\"\n            ? DateTime.Parse((string)value.ToClrValue(), CultureInfo.InvariantCulture)\n            : throw new InvalidCastException($\"Cannot convert remote {value.Type} value to DateTime.\");\n    }\n\n    public override decimal GetDecimal(int ordinal)\n    {\n        return CurrentValue(ordinal).GetDecimal();\n    }\n\n    public override double GetDouble(int ordinal)\n    {\n        return CurrentValue(ordinal).GetDouble();\n    }\n\n    public override Type GetFieldType(int ordinal)\n    {\n        EnsureOpen();\n        ValidateOrdinal(ordinal);\n\n        if (ordinal < CurrentResult.Columns.Count","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs#L83-L119","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nDateTime created = reader.GetDateTime(2); // column holds unix-epoch integer -> InvalidCastException\n\n// after\nobject raw = reader.GetValue(2);\nDateTime created = raw switch\n{\n    string s => DateTime.Parse(s, CultureInfo.InvariantCulture),\n    long epoch => DateTimeOffset.FromUnixTimeSeconds(epoch).UtcDateTime,\n    DBNull => throw new InvalidOperationException(\"created must not be null\"),\n    _ => throw new InvalidCastException()\n};","handlingStrategy":"validation","validationCode":"// before GetDateTime: confirm the cell is text and not null\nbool CanGetDateTime(DbDataReader reader, int ordinal) =>\n    !reader.IsDBNull(ordinal) && reader.GetDataTypeName(ordinal) == \"TEXT\";","typeGuard":"static bool IsTextColumn(DbDataReader r, int ord) => r.GetDataTypeName(ord).Equals(\"TEXT\", StringComparison.OrdinalIgnoreCase);","tryCatchPattern":"try { var dt = reader.GetDateTime(i); }\ncatch (InvalidCastException) { var raw = reader.GetValue(i); /* convert epoch/Julian manually */ }","preventionTips":["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."],"tags":["dotnet","ado-net","type-conversion","datetime","turso-data"],"backgroundTag":"db-type-conversion-failed","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}