tursodatabase/turso · error · SqliteException

throw SqliteCommand.ToSqliteException(ex);

Error message

throw SqliteCommand.ToSqliteException(ex);

What it means

SqliteBatch.ExecuteNonQuery catches TursoException thrown by the underlying Turso batch execution and rethrows it as a SqliteException via SqliteCommand.ToSqliteException, so ADO.NET consumers see the familiar Microsoft.Data.Sqlite exception type with the mapped SQLite result code. The 'message' here is the throw statement itself; the real failure is whatever database error the TursoException carried.

Source

Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs:93

    public override int ExecuteNonQuery()
    {
        var state = BuildBatch();
        if (state.Batch is null)
            return SetRecordsAffected(state);

        using (state.Batch)
        {
            WaitForOpenReader(state.Statements);
            _activeBatch = state.Batch;
            try
            {
                var recordsAffected = state.Batch.ExecuteNonQuery();
                SetRecordsAffected(state);
                return recordsAffected;
            }
            catch (TursoException ex)
            {
                throw SqliteCommand.ToSqliteException(ex);
            }
            finally
            {
                _activeBatch = null;
            }
        }
    }

    public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        var state = BuildBatch();
        if (state.Batch is null)
            return SetRecordsAffected(state);

        await using (state.Batch)
        {
            await WaitForOpenReaderAsync(state.Statements, cancellationToken).ConfigureAwait(false);

View on GitHub (pinned to 6c72522679)

Solutions

  1. Inspect the resulting SqliteException's SqliteErrorCode/SqliteErrorRcExt value to identify the underlying SQLite error and fix the SQL/data accordingly.
  2. Wrap ExecuteNonQuery in try/catch on SqliteException and handle expected codes (e.g. 19 for constraint violation).
  3. Test the batch's statements individually to find which one fails.
  4. Use scripts/diff.sh or the CLI to run the failing SQL against sqlite3/tursodb for diagnosis.

Example fix

// before
batch.ExecuteNonQuery(); // unhandled SqliteException on failure

// after
try { batch.ExecuteNonQuery(); }
catch (SqliteException ex) when (ex.SqliteErrorCode == 19)
{
    // handle constraint violation
}
Defensive patterns

Strategy: try-catch

Try / catch

try { batch.ExecuteNonQuery(); }
catch (SqliteException ex)
{
    switch (ex.SqliteErrorCode)
    {
        case 19: /* constraint violation */ break;
        case 5: /* busy: retry */ break;
        default: throw;
    }
}

Prevention

When it happens

Trigger: Executing a DbBatch against Turso where any command in the batch fails at the engine level: SQL syntax error, constraint violation, locked database, IO failure - anything surfacing as TursoException.

Common situations: Migrating code from Microsoft.Data.Sqlite to Turso.Data.Sqlite and executing batches with invalid SQL or constraint violations; unhandled duplicate-key inserts inside batched statements.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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