tursodatabase/turso · error · InvalidOperationException

The data reader has no result sets.

Error message

The data reader has no result sets.

What it means

The remote reader keeps a list of RemoteStatementResult sets; the CurrentResult property throws InvalidOperationException when that list is empty. Nearly every member (FieldCount, HasRows, Read, GetName, GetValue) flows through CurrentResult, so a reader constructed with zero result payloads is unusable rather than empty.

Source

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

    {
        return cancellationToken.IsCancellationRequested
            ? Task.FromCanceled<bool>(cancellationToken)
            : Task.FromResult(Read());
    }

    public override int Depth => 0;

    public override IEnumerator GetEnumerator()
    {
        return new DbEnumerator(this, closeReader: false);
    }

    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");

View on GitHub (pinned to 6c72522679)

Solutions

  1. Use ExecuteNonQuery for INSERT/UPDATE/DELETE/DDL instead of a reader.
  2. If you must branch, decide based on the statement kind or the command API you called, not on reader.FieldCount (which itself throws here).
  3. When running batches, iterate with NextResult() and treat each set according to whether it has columns.
  4. Avoid manually constructing RemoteStatementResult lists with zero entries in tests and harnesses.

Example fix

// before
using var reader = command.ExecuteReader(); // INSERT statement, no result set
Console.WriteLine(reader.FieldCount); // throws: no result sets

// after
int affected = command.ExecuteNonQuery();
Console.WriteLine(affected);
Defensive patterns

Strategy: validation

Validate before calling

// choose the API by statement kind before executing
bool isQuery = sql.TrimStart().StartsWith("SELECT", StringComparison.OrdinalIgnoreCase);
if (isQuery) { using var r = command.ExecuteReader(); /* ... */ }
else { var n = command.ExecuteNonQuery(); }

Try / catch

try { var fc = reader.FieldCount; }
catch (InvalidOperationException) { /* statement produced no result set; nothing to read */ }

Prevention

When it happens

Trigger: Calling ExecuteReader-style APIs on a statement that produces no result payload (INSERT, UPDATE, DELETE, CREATE TABLE, PRAGMA without rows) and then touching any reader property; a code path that constructs TursoRemoteDataReader with an empty results list; an empty or comment-only batch.

Common situations: Generic helper methods that always use ExecuteReader regardless of statement kind; batches mixing DDL and SELECT where the first result has no columns; porting code from SqliteClient where a reader for a non-query is merely empty.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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