tursodatabase/turso · error · SqliteException
5
5
Error message
SQLite Error {errorCode}: '{message}'. What it means
BackupDatabase deliberately throws SqliteException with native error code 5 (SQLITE_BUSY, 'database is locked') when the source connection has an active transaction. A physical copy cannot be taken while the connection's own transaction holds locks on the database; rather than attempting a backup that would contend, the provider translates this precondition into the standard busy error. This is raised before any schema or row copying starts.
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs:486
{
_pendingExtensions.Add((file, proc));
return;
}
LoadExtensionCore(file, proc);
}
public virtual void BackupDatabase(SqliteConnection destination)
=> BackupDatabase(destination, "main", "main");
public virtual void BackupDatabase(SqliteConnection destination, string destinationName, string sourceName)
{
ThrowIfManagedLocalOnly(nameof(BackupDatabase));
if (_database is null)
throw new InvalidOperationException(Properties.Resources.CallRequiresOpenConnection("BackupDatabase"));
ArgumentNullException.ThrowIfNull(destination);
if (Transaction is not null)
throw new SqliteException(Properties.Resources.SqliteNativeError(5, "database is locked"), 5);
if (destination.State != ConnectionState.Open)
destination.Open();
foreach (var createSql in GetSchemaSql())
destination.ExecuteNonQuery(createSql);
foreach (var tableName in GetUserTableNames())
CopyTableRows(destination, tableName);
}
public new virtual SqliteCommand CreateCommand() => new(this) { Transaction = Transaction };
protected override DbCommand CreateDbCommand() => CreateCommand();
protected override DbBatch CreateDbBatch()
{
if (_managedConnection is null)
{View on GitHub (pinned to 6c72522679)
Solutions
- Commit or roll back (and dispose) the source transaction before calling BackupDatabase.
- Restructure so backups run outside transaction scopes (e.g. a dedicated connection/path with no active Transaction).
- If you need a consistent copy mid-workflow, commit first, then back up, then continue in a new transaction.
Example fix
// before
using var conn = new SqliteConnection(cs);
conn.Open();
using var tx = conn.BeginTransaction();
InsertRows(conn);
conn.BackupDatabase(dst); // throws SqliteException code 5: database is locked
// after
using var conn = new SqliteConnection(cs);
conn.Open();
using (var tx = conn.BeginTransaction())
{
InsertRows(conn);
tx.Commit();
}
conn.BackupDatabase(dst); // no active transaction -> succeeds Defensive patterns
Strategy: validation
Validate before calling
static void BackupOutsideTransactions(SqliteConnection src, string dstCs)
{
if (src.Transaction is not null)
throw new InvalidOperationException($"Commit or roll back the active transaction before backup.");
if (src.State != ConnectionState.Open) src.Open();
using var dst = new SqliteConnection(dstCs);
dst.Open();
src.BackupDatabase(dst);
} Type guard
static bool HasActiveTransaction(SqliteConnection conn) => conn.Transaction is not null;
Try / catch
try
{
src.BackupDatabase(dst);
}
catch (SqliteException ex) when (ex.SqliteErrorCode == 5)
{
// SQLITE_BUSY from an active source transaction (or external locker):
// settle transactions, then retry the backup once.
throw new InvalidOperationException("Backup blocked by an active transaction; commit/rollback and retry.", ex);
} Prevention
- Never call BackupDatabase from inside a transactional scope on the source connection.
- Schedule backups from a path that provably holds no open SqliteTransaction.
- Treat error code 5 during backup as a lifecycle bug to fix, not a transient condition to blindly retry.
When it happens
Trigger: 'using var tx = conn.BeginTransaction(); ... conn.BackupDatabase(dst);' on the same connection; calling BackupDatabase from code that runs inside a unit-of-work scope holding a transaction; committing asynchronously and backing up before the commit lands.
Common situations: Backup jobs triggered while writes are in flight, repository-level backup helpers invoked inside transactional service methods, and test teardown that snapshots the database without unwinding the test transaction.
Related errors
- {method} requires an open connection.
- Parallel transactions are not supported.
- Encryption is not supported by {libraryName}.
- Missing parameter values for {parameters}.
- Parameter name {parameterName} is ambiguous.
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/3d830c3b8d909809.
Report an issue: GitHub.