tursodatabase/turso · error · InvalidOperationException

The data is NULL at ordinal {ordinal}.

Error message

The data is NULL at ordinal {ordinal}.

What it means

InvalidOperationException thrown by GetFieldValue<T> when the requested column holds NULL: the reader returns DBNull.Value and, unless T is exactly DBNull, the call fails with 'The data is NULL at ordinal {ordinal}'. This is the strongly-typed accessor equivalent of SQL null leakage into non-nullable CLR types. Note that Nullable<T> does not help — GetFieldValue<int?> on a NULL column still throws because the DBNull check happens before the target-type switch.

Source

Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteDataReader.cs:248

        ValidateOrdinal(ordinal);
        var valueType = TursoBindings.GetValue(statement, ordinal).ValueType;
        var declaredType = GetDeclaredTypeName(ordinal);
        if (!string.IsNullOrEmpty(declaredType))
            return GetClrTypeFromSqliteType(declaredType, valueType);

        return GetClrTypeFromSqliteType(GetDataTypeName(ordinal), valueType);
    }

    public override T GetFieldValue<T>(int ordinal)
    {
        EnsureOpen();
        var value = GetValue(ordinal);
        if (value == DBNull.Value)
        {
            if (typeof(T) == typeof(DBNull))
                return (T)value;

            throw new InvalidOperationException(Properties.Resources.CalledOnNullValue(ordinal));
        }

        if (typeof(T) == typeof(DBNull))
            throw new InvalidCastException();

        var targetType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);

        if (targetType == typeof(DateOnly))
            return (T)(object)DateOnly.FromDateTime(GetDateTime(ordinal));

        if (targetType == typeof(TimeOnly))
            return (T)(object)TimeOnly.FromTimeSpan(GetTimeSpan(ordinal));

        if (targetType == typeof(DateTime))
            return (T)(object)GetDateTime(ordinal);

        if (targetType == typeof(DateTimeOffset))
            return (T)(object)GetDateTimeOffset(ordinal);

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Guard with reader.IsDBNull(ordinal) before the call and supply a default: var v = reader.IsDBNull(i) ? 0 : reader.GetFieldValue<int>(i).
  2. Handle NULL in SQL with COALESCE/IFNULL so the column never reaches the reader as NULL.
  3. If the null case is meaningful, fetch it explicitly: var v = reader.IsDBNull(i) ? (int?)null : reader.GetFieldValue<int>(i).

Example fix

// before
var name = reader.GetFieldValue<string>(ordinal); // throws when NULL

// after
var name = reader.IsDBNull(ordinal) ? null : reader.GetFieldValue<string>(ordinal);
Defensive patterns

Strategy: validation

Validate before calling

var value = reader.IsDBNull(ordinal) ? defaultIfNull : reader.GetFieldValue<int>(ordinal);

Type guard

static T? GetOrNull<T>(SqliteDataReader r, int i) where T : struct
    => r.IsDBNull(i) ? null : r.GetFieldValue<T>(i);

Try / catch

try { v = reader.GetFieldValue<string>(i); }
catch (InvalidOperationException ex) when (ex.Message.Contains("NULL"))
{ v = fallback; }

Prevention

When it happens

Trigger: SELECT NULL AS x then reader.GetFieldValue<int>(0); a nullable table column (e.g. deleted_at) that is NULL for the current row, read with GetFieldValue<DateTime>; computed columns like COUNT(*)/MAX(...) returning NULL on empty input.

Common situations: Optional fields becoming NULL after a schema migration adds a column; aggregate/LEFT JOIN queries producing NULLs the app did not anticipate; switching from GetString to GetFieldValue<T> assuming nullable semantics.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/e1382edb17e6e4be. Report an issue: GitHub.