{"record":{"id":"a3987ee56748d3f3","repo":"tursodatabase/turso","slug":"throw-sqlitecommand-tosqliteexception-ex","errorCode":null,"errorMessage":"throw SqliteCommand.ToSqliteException(ex);","messagePattern":"throw SqliteCommand\\.ToSqliteException\\(ex\\);","errorType":"exception","errorClass":"SqliteException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs","lineNumber":93,"sourceCode":"    public override int ExecuteNonQuery()\n    {\n        var state = BuildBatch();\n        if (state.Batch is null)\n            return SetRecordsAffected(state);\n\n        using (state.Batch)\n        {\n            WaitForOpenReader(state.Statements);\n            _activeBatch = state.Batch;\n            try\n            {\n                var recordsAffected = state.Batch.ExecuteNonQuery();\n                SetRecordsAffected(state);\n                return recordsAffected;\n            }\n            catch (TursoException ex)\n            {\n                throw SqliteCommand.ToSqliteException(ex);\n            }\n            finally\n            {\n                _activeBatch = null;\n            }\n        }\n    }\n\n    public override async Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)\n    {\n        cancellationToken.ThrowIfCancellationRequested();\n        var state = BuildBatch();\n        if (state.Batch is null)\n            return SetRecordsAffected(state);\n\n        await using (state.Batch)\n        {\n            await WaitForOpenReaderAsync(state.Statements, cancellationToken).ConfigureAwait(false);","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the resulting SqliteException's SqliteErrorCode/SqliteErrorRcExt value to identify the underlying SQLite error and fix the SQL/data accordingly.","Wrap ExecuteNonQuery in try/catch on SqliteException and handle expected codes (e.g. 19 for constraint violation).","Test the batch's statements individually to find which one fails.","Use scripts/diff.sh or the CLI to run the failing SQL against sqlite3/tursodb for diagnosis."],"exampleFix":"// before\nbatch.ExecuteNonQuery(); // unhandled SqliteException on failure\n\n// after\ntry { batch.ExecuteNonQuery(); }\ncatch (SqliteException ex) when (ex.SqliteErrorCode == 19)\n{\n    // handle constraint violation\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { batch.ExecuteNonQuery(); }\ncatch (SqliteException ex)\n{\n    switch (ex.SqliteErrorCode)\n    {\n        case 19: /* constraint violation */ break;\n        case 5: /* busy: retry */ break;\n        default: throw;\n    }\n}","preventionTips":["Test each batch statement in the tursodb CLI before shipping it.","Validate SQL strings against the schema (migrations applied) at startup.","Handle expected SQLite result codes explicitly instead of letting them bubble."],"tags":["dotnet","ado-net","batch","exception-translation"],"backgroundTag":"sql-query-failed","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-09-06T07:15:26.990Z","contentChangedAt":"2026-09-06T07:15:26.990Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}