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
- Wrap value access in while (await reader.ReadAsync()) { ... } (or `if` for single-row expectations).
- Use ExecuteScalar for single-value queries instead of a reader.
- After NextResult(), always call Read() again before touching values.
- 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
- Always gate value access behind Read()/ReadAsync() returning true.
- Call Read() again after every NextResult().
- Use ExecuteScalar for single-value queries instead of a reader.
- Treat HasRows as a preview, not a positioning operation.
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
- 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/4ce15fae190ed5d9.
Report an issue: GitHub.