tursodatabase/turso · error · InvalidOperationException

Connection must be set before preparing a command.

Error message

Connection must be set before preparing a command.

What it means

Prepare() compiles CommandText into a native statement through the connection's database handle, so it requires a bound connection (TursoCommand.cs:152-155). Calling Prepare — or any local Execute, which calls Prepare internally — while Connection is null throws InvalidOperationException before any SQL is parsed.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoCommand.cs:161

    public override async Task<object?> ExecuteScalarAsync(CancellationToken cancellationToken)
    {
        await using var reader = await ExecuteDbDataReaderAsync(CommandBehavior.Default, cancellationToken).ConfigureAwait(false);
        return await reader.ReadAsync(cancellationToken).ConfigureAwait(false)
            ? reader.GetValue(0)
            : null;
    }

    public override void Prepare()
    {
        using var syncOperation = _connection?.EnterSyncOperation();
        PrepareCore();
    }

    private void PrepareCore()
    {
        if (_connection is null)
            throw new InvalidOperationException("Connection must be set before preparing a command.");
        if (string.IsNullOrWhiteSpace(CommandText))
            throw new InvalidOperationException("CommandText must be set before preparing a command.");
        ValidateTransaction();
        if (_connection.IsRemote)
            return;

        TursoStatementHandle? preparedStatement = null;
        try
        {
            var sql = RewriteFacadePragmas(CommandText, _connection);
            preparedStatement = TursoBindings.PrepareStatement(_connection.Turso, sql);
            var parameterCount = TursoBindings.GetParameterCount(preparedStatement);
            var boundParameters = new bool[parameterCount + 1];

            for (var i = 0; i < _parameterCollection.Count; i++)
            {
                var parameter = _parameterCollection[i] as TursoParameter;
                if (parameter == null)

View on GitHub (pinned to c1e5928725)

Solutions

  1. Assign the connection first: cmd.Connection = conn; then call Prepare().
  2. Prefer creating commands from the connection: using var cmd = conn.CreateCommand(); so the binding always exists.
  3. Null-check cmd.Connection in shared helpers and throw your own descriptive error early.

Example fix

// before
var cmd = new TursoCommand { CommandText = "SELECT 1" };
cmd.Prepare(); // throws InvalidOperationException

// after
using var conn = new TursoConnection(cs);
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT 1";
cmd.Prepare();
Defensive patterns

Strategy: validation

Validate before calling

if (cmd.Connection is not TursoConnection conn || conn.State != ConnectionState.Open)
    throw new InvalidOperationException("Open a TursoConnection and bind it to the command first.");

Prevention

When it happens

Trigger: new TursoCommand { CommandText = "SELECT 1" }.Prepare(); or cmd.ExecuteReader() on a command whose Connection was never assigned or was set back to null.

Common situations: Object-initializer ordering mistakes where Prepare/Execute precedes Connection assignment; unit tests constructing commands standalone; long-lived command objects reused after the connection was unbound; forgetting that Turso (unlike SqlClient pooling) does not auto-open/attach.

Related errors


AI-assisted analysis of tursodatabase/turso@c1e5928725 (2026-08-31). Data as JSON: /api/errors/360a18ad0ef14cbd. Report an issue: GitHub.