tursodatabase/turso · error · InvalidOperationException

Encryption is not supported by {libraryName}.

Error message

Encryption is not supported by {libraryName}.

What it means

Open() throws InvalidOperationException when the connection string contains a non-empty Password, because the Turso SQLite-compatible provider (backed by the e_sqlite3 native library) is built without encryption support (no SQLITE_HAS_CODEC/SEE). The check happens before any file is opened, so no database is created or touched. This intentionally fails fast instead of silently ignoring the password and writing an unencrypted file.

Source

Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs:95

    {
        get => _readUncommitted;
        set => _readUncommitted = value;
    }

    // The SQLite version Turso tracks (SQLITE_VERSION in core/dialect/sqlite.rs).
    public override string ServerVersion => "3.50.4";

    public override ConnectionState State => _database is null ? ConnectionState.Closed : ConnectionState.Open;

    protected override DbProviderFactory DbProviderFactory => SqliteFactory.Instance;

    public override void Open()
    {
        ObjectDisposedException.ThrowIf(_disposed, this);
        if (_database is not null)
            throw new InvalidOperationException("The connection is already open.");
        if (!string.IsNullOrEmpty(_connectionOptions.Password))
            throw new InvalidOperationException(Properties.Resources.EncryptionNotSupported("e_sqlite3"));

        var originalState = State;
        var filename = NormalizeDataSource(_connectionOptions);
        var readOnly = _connectionOptions.Mode == SqliteOpenMode.ReadOnly;
        var sharedMemoryPath = IsSharedMemory(_connectionOptions) ? RegisterSharedMemoryFile(filename) : null;
        try
        {
            _database = TursoBindings.OpenDatabase(filename);
            _dataSource = filename;
            _readOnly = readOnly;
            _sharedMemoryPath = sharedMemoryPath;
            ApplyExtensionSettings();
            ApplyConnectionOptions();
            RegisterScalarFunctions();
            RegisterAggregateFunctions();
            RegisterCollations();
            LoadPendingExtensions();
            OnStateChange(new StateChangeEventArgs(originalState, State));

View on GitHub (pinned to 244cde92a7)

Solutions

  1. Remove the Password entry from the connection string (it is never honored by this provider).
  2. If data-at-rest encryption is required, use an approach outside this provider: full-disk/OS file encryption, EFS/LUKS, or a provider that ships SQLCipher and convert the file there.
  3. Encrypt/decrypt sensitive columns at the application layer (e.g. AES via a UDF or in code) instead of whole-file encryption.

Example fix

// before
var cs = new SqliteConnectionStringBuilder { DataSource = "enc.db", Password = "secret" };
using var conn = new SqliteConnection(cs.ToString());
conn.Open(); // throws: Encryption is not supported by e_sqlite3

// after
var cs = new SqliteConnectionStringBuilder { DataSource = "plain.db" };
using var conn = new SqliteConnection(cs.ToString());
conn.Open(); // encrypt at the application layer if needed
Defensive patterns

Strategy: validation

Validate before calling

static string StripUnsupportedPassword(string cs)
{
    var b = new SqliteConnectionStringBuilder(cs);
    if (b.TryGetValue("Password", out var pwd) && !string.IsNullOrEmpty(pwd?.ToString()))
    {
        b.Remove("Password");
        // decide policy here: fail loudly, or proceed unencrypted knowingly
    }
    return b.ConnectionString;
}

// usage: new SqliteConnection(StripUnsupportedPassword(cs))

Try / catch

null

Prevention

When it happens

Trigger: 'Data Source=enc.db;Password=secret' in the connection string; connection strings copied from SQLCipher, System.Data.SQLite (with codec), or SEE-based deployments; shared config files that carry a Password key for all providers.

Common situations: Migrating an encrypted database from another SQLite distribution and assuming the Turso provider reads the same option; multi-provider config where a global Password property is applied to every connection string; leftover Password keys from an earlier stack.

Related errors


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