tursodatabase/turso · error · TursoServerlessException

SQL execution failed

Error message

SQL execution failed

What it means

ExecuteAsync streams a cursor batch and inspects each result entry. An entry of type step_error or error throws TursoServerlessException with the server's message, falling back to 'SQL execution failed' only when the error entry carried no message. It marks a statement that failed on the server at execute time.

Source

Thrown at bindings/dotnet/src/Turso.Serverless.Client/TursoSession.cs:127

                        rows.Add(new TursoRow(values, rowColumns ?? []));
                    }

                    break;
                case "step_end":
                    if (entry.AffectedRowCount is { } affected)
                    {
                        rowsAffected = affected;
                    }

                    if (entry.LastInsertRowid is { } rowid)
                    {
                        lastInsertRowid = rowid;
                    }

                    break;
                case "step_error":
                case "error":
                    throw new TursoServerlessException(entry.Error?.Message ?? "SQL execution failed", entry.Error?.Code);
            }
        }

        UpdateAutocommitForTransactionControlStatement(sql);
        return new TursoResultSet(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
    }

    internal async Task<TursoBatchResult> BatchAsync(IReadOnlyList<HranaStatement> statements, TursoBatchMode? mode, TimeSpan? queryTimeout, CancellationToken cancellationToken)
    {
        var userSteps = statements.Select(static s => new HranaBatchStep { Statement = s }).ToList();

        List<HranaBatchStep> steps;
        var firstUserStepIdx = 0;
        var lastUserStepIdx = userSteps.Count - 1;
        var beginIdx = -1;
        var commitIdx = -1;
        var rollbackIdx = -1;

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Inspect the exception Message and Code (e.g. SQLITE_CONSTRAINT_UNIQUE) — the server message is present in the common case
  2. Fix the data or statement per the constraint named by the code; add pre-validation for the specific constraint
  3. For lock/busy codes, retry with backoff or shorten the transaction
  4. Reproduce with turso db shell against the same database and row

Example fix

// before
await conn.ExecuteAsync("INSERT INTO users(id) VALUES (@id)", cmd); // duplicate id

// after
var exists = await conn.ExecuteAsync("SELECT 1 FROM users WHERE id=@id", cmd);
if (exists.Rows.Count == 0)
    await conn.ExecuteAsync("INSERT INTO users(id) VALUES (@id)", cmd);
Defensive patterns

Strategy: try-catch

Validate before calling

if (await ExistsAsync(conn, "users", row.Id)) return; // pre-check for the common UNIQUE case

Try / catch

try { await conn.ExecuteAsync(sql, cmd, timeout, ct); } catch (TursoServerlessException ex) when (ex.Code?.StartsWith("SQLITE_CONSTRAINT") == true) { log.Warn($"constraint {ex.Code}: {ex.Message}"); throw; } catch (TursoServerlessException ex) when (ex.Code is "SQLITE_BUSY" or "SQLITE_LOCKED") { await Task.Delay(backoff); await conn.ExecuteAsync(sql, cmd, timeout, ct); }

Prevention

When it happens

Trigger: Runtime SQL failures: UNIQUE/FOREIGN KEY/CHECK constraint violations, NOT NULL on insert, type affinity errors, or accessing a locked table — e.g. INSERT duplicating a primary key that validation did not catch.

Common situations: Concurrent writers violating constraints, payload regressions feeding bad data, statements valid against one schema but failing against another, transaction conflicts on busy databases.

Related errors


AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20). Data as JSON: /api/errors/520f3b901a1e82e6. Report an issue: GitHub.