tursodatabase/turso · error · InvalidOperationException

No current row. Call Read before accessing values.

Error message

No current row. Call Read before accessing values.

What it means

The reader starts at row index -1 and only Read() advances it; CurrentValue (backing every GetX, GetValue, the indexers, and IsDBNull) throws InvalidOperationException whenever the index is outside the current result's rows. That covers both before-first-Read and after-Read-returned-false positions, including after NextResult() reset the index.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoRemoteDataReader.cs:309

    private RemoteStatementResult CurrentResult
    {
        get
        {
            if (_results.Count == 0)
                throw new InvalidOperationException("The data reader has no result sets.");

            return _results[_resultIndex];
        }
    }

    private bool HasCurrentRow => _rowIndex >= 0 && _rowIndex < CurrentResult.Rows.Count;

    private RemoteResponseValue CurrentValue(int ordinal)
    {
        EnsureOpen();
        if (!HasCurrentRow)
            throw new InvalidOperationException("No current row. Call Read before accessing values.");

        ValidateOrdinal(ordinal);
        var row = CurrentResult.Rows[_rowIndex];
        if (ordinal >= row.Count)
            throw new IndexOutOfRangeException($"column ordinal {ordinal} is out of range");

        return row[ordinal];
    }

    private static long CopyArray<T>(T[] source, long dataOffset, T[]? buffer, int bufferOffset, int length)
    {
        ArgumentOutOfRangeException.ThrowIfNegative(dataOffset);
        ArgumentOutOfRangeException.ThrowIfNegative(bufferOffset);
        ArgumentOutOfRangeException.ThrowIfNegative(length);

        if (dataOffset >= source.LongLength)
            return 0;

View on GitHub (pinned to 6c72522679)

Solutions

  1. Wrap value access in while (await reader.ReadAsync()) { ... } (or `if` for single-row expectations).
  2. Use ExecuteScalar for single-value queries instead of a reader.
  3. After NextResult(), always call Read() again before touching values.
  4. Treat HasRows as a hint about data existing, never as permission to skip Read().

Example fix

// before
using var reader = command.ExecuteReader();
var name = reader.GetString(0); // Read() never called -> throws

// after
using var reader = command.ExecuteReader();
while (reader.Read())
{
    var name = reader.GetString(0);
}
Defensive patterns

Strategy: validation

Validate before calling

// only access values from a positioned reader
if (reader.Read())
{
    var value = reader.GetString(0);
}

Prevention

When it happens

Trigger: Calling any value accessor without calling Read() first; continuing to access values after Read() returned false; calling NextResult() and then reading values without calling Read() again on the new set; assuming HasRows == true implies a current row.

Common situations: Classic ADO.NET misuse in freshly written data access code; helper that does reader[0] for a known-single-row query assuming implicit positioning; early-exit loops that break out of Read() and then log the row.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20). Data as JSON: /api/errors/4ce15fae190ed5d9. Report an issue: GitHub.