tursodatabase/turso · error · InvalidOperationException

Embedded replica '{path}' is already open exclusively.

Error message

Embedded replica '{path}' is already open exclusively.

What it means

AcquireAsync enforces sharing rules per replica path: if an existing entry is not flagged for pooling, or the new request is not pooling, the path is already held exclusively and a second acquisition throws InvalidOperationException. Only pooled, compatible openers may share a replica.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoReplicaRegistry.cs:41

            var database = await TursoSyncDatabase
                .CreateAsync(options, cancellationToken)
                .ConfigureAwait(false);
            return Lease.CreateStandalone(
                database,
                new TursoAutomaticSyncCoordinator(database, syncInterval, timeProvider));
        }

        var path = Path.GetFullPath(options.Path);
        var fingerprint = Fingerprint.Create(options, syncInterval);
        Entry entry;
        lock (Gate)
        {
            if (Entries.TryGetValue(path, out entry!))
            {
                if (entry.Closing)
                    throw new InvalidOperationException($"Embedded replica '{path}' is closing.");
                if (!pooling || !entry.Pooling)
                    throw new InvalidOperationException($"Embedded replica '{path}' is already open exclusively.");
                if (entry.Fingerprint != fingerprint)
                    throw new InvalidOperationException($"Embedded replica '{path}' is already open with different options.");

                checked
                {
                    entry.ReferenceCount++;
                }
            }
            else
            {
                entry = new Entry(path, pooling, fingerprint)
                {
                    ReferenceCount = 1,
                };
                entry.Initialization = InitializeAsync(entry, options, syncInterval, timeProvider);
                Entries.Add(path, entry);
            }
        }

View on GitHub (pinned to 6c72522679)

Solutions

  1. Open all connections to a given replica path with pooling enabled so they share the registry entry.
  2. Ensure prior exclusive connections are disposed before opening the replica again.
  3. Search the codebase for other TursoConnection instances using the same path and centralize replica access.
  4. Catch InvalidOperationException and reuse an existing connection from your own DI/pool layer instead.

Example fix

// before
var a = new TursoConnection(replicaPath); await a.OpenAsync(); // exclusive
var b = new TursoConnection(replicaPath); await b.OpenAsync(); // throws
// after
var a = new TursoConnection(pooledReplicaConnString); await a.OpenAsync();
var b = new TursoConnection(pooledReplicaConnString); await b.OpenAsync(); // shares registry entry
Defensive patterns

Strategy: try-catch

Validate before calling

// Track openings in app code:
if (openReplicaPaths.Contains(path) && !requestIsPooling)
    throw new InvalidOperationException($"Replica '{path}' is already open; enable pooling to share it.");

Try / catch

try { conn = await registry.AcquireAsync(path, pooling, fingerprint); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already open exclusively"))
{ conn = reuseExistingConnection(path); }

Prevention

When it happens

Trigger: Opening a second connection to the same embedded replica path when the first was opened non-pooling (exclusive), or opening an exclusive (non-pooling) connection while a pooled one already exists.

Common situations: Two parts of an app each creating their own connection to the same replica file with different pooling settings; a background sync service holding an exclusive replica while the app tries to open another connection; stale connection leaked in a long-running process.

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


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06). Data as JSON: /api/errors/e81cdb456ea45ea8. Report an issue: GitHub.