tursodatabase/turso · error · InvalidOperationException
A SqliteConnection wrapping a TursoConnection must remain a
Error message
A SqliteConnection wrapping a TursoConnection must remain a direct remote or embedded replica connection.
What it means
This InvalidOperationException is thrown by the SqliteConnection.ConnectionString setter when a connection that already wraps a TursoConnection is assigned a local connection string. The wrapper must stay on the managed direct-remote/embedded-replica backend for its lifetime.
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs:74
_managedConnection = connection;
_ownsManagedConnection = ownsConnection;
_wrapsManagedConnection = true;
_readOnly = options.Mode == SqliteOpenMode.ReadOnly;
}
[AllowNull]
public override string ConnectionString
{
get => _connectionOptions.ConnectionString;
set
{
if (State == ConnectionState.Open)
throw new InvalidOperationException(Properties.Resources.ConnectionStringRequiresClosedConnection);
var options = new SqliteConnectionStringBuilder(value);
if (_wrapsManagedConnection && options.IsLocal)
{
throw new InvalidOperationException(
"A SqliteConnection wrapping a TursoConnection must remain a direct remote or embedded replica connection.");
}
ConfigureManagedConnection(options);
_connectionOptions = options;
_defaultTimeout = null;
}
}
public override string Database => _managedConnection?.Database ?? "main";
public override string DataSource => _managedConnection?.DataSource ?? _dataSource ?? _connectionOptions.DataSource;
public int DefaultTimeout
{
get => _defaultTimeout ?? _connectionOptions.DefaultTimeout;
set
{View on GitHub (pinned to 6c72522679)
Solutions
- Assign only direct remote or embedded replica connection strings to a wrapping SqliteConnection
- Create a new, separate SqliteConnection(connectionString) for local usage instead of mutating the wrapper
- Track the _wrapsManagedConnection flag in your own code and branch before reassigning the connection string
Example fix
// before
managedWrapper.ConnectionString = "Data Source=local.db"; // throws
// after
var localConn = new SqliteConnection("Data Source=local.db"); Defensive patterns
Strategy: validation
Validate before calling
if (new SqliteConnectionStringBuilder(cs).IsLocal && wrapsManaged)
throw new InvalidOperationException("Use a fresh connection for local targets."); Try / catch
try { conn.ConnectionString = cs; }
catch (InvalidOperationException ex) when (ex.Message.Contains("must remain"))
{
conn = new SqliteConnection(cs);
} Prevention
- Never mutate ConnectionString on wrapped connections
- Branch local/remote at connection creation time
When it happens
Trigger: Setting conn.ConnectionString = "Data Source=local.db" (or any IsLocal string) on a SqliteConnection constructed around a TursoConnection, whether the connection is open or closed (the open-state guard fires first if open).
Common situations: Code that reuses one SqliteConnection object and swaps connection strings between local and remote targets; config-driven connection strings pointing to a local file for a wrapper meant to be remote.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Embedded replica connections are not supported yet by the .N
- Sync Interval requires embedded replica support, which is no
- Auth Token requires a remote Turso URL Data Source.
- Pooling is not supported for embedded replica connections ye
- Automatic sync is not supported for embedded replica connect
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06).
Data as JSON: /api/errors/a31c5662fd51bdb8.
Report an issue: GitHub.