tursodatabase/turso · error · InvalidOperationException

Embedded replica lease ownership is unbalanced.

Error message

Embedded replica lease ownership is unbalanced.

What it means

ReleaseReference decrements the reference count of a pooled embedded replica entry when a connection is disposed. The registry expects every Release to be paired with exactly one Acquire; if the count is already <= 0 the lease bookkeeping is corrupt, so it throws this InvalidOperationException to surface the internal bug.

Source

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

        }
        catch
        {
            lock (Gate)
            {
                if (Entries.TryGetValue(entry.Path, out var current) && ReferenceEquals(current, entry))
                    Entries.Remove(entry.Path);
            }
            throw;
        }
    }

    private static Exception? ReleaseReference(Entry entry)
    {
        Holder? holder;
        lock (Gate)
        {
            if (entry.ReferenceCount <= 0)
                throw new InvalidOperationException("Embedded replica lease ownership is unbalanced.");
            entry.ReferenceCount--;
            if (entry.ReferenceCount != 0)
            {
                var status = entry.Holder?.Coordinator.Status;
                return status?.State == TursoAutomaticSyncState.Faulted
                    ? status.LastException
                    : null;
            }

            entry.Closing = true;
            entry.InitializationCancellation.Cancel();
            holder = entry.Holder;
            if (holder is null)
            {
                _ = DisposeAfterInitializationAsync(entry);
                return null;
            }
        }

View on GitHub (pinned to 6c72522679)

Solutions

  1. Ensure each connection is disposed exactly once (don't call both Close and Dispose, don't dispose inside and outside a using block).
  2. Check for code that shares one TursoConnection across threads and disposes it concurrently.
  3. If it appears without obvious double-dispose, report it as a bug in Turso.Data reference counting.
  4. Guard disposal with an idempotent wrapper around your connection lifetime management.

Example fix

// before
tursoConn.Dispose();
// ... later, accidental second release
tursoConn.Dispose();

// after: single idempotent disposal
if (!tursoDisposed) { tursoConn.Dispose(); tursoDisposed = true; }
Defensive patterns

Strategy: try-catch

Try / catch

try { tursoConn.Dispose(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("lease ownership is unbalanced"))
{
    // bookkeeping bug or double dispose; log and stop touching this connection
}

Prevention

When it happens

Trigger: Disposing/closing a TursoConnection that acquired an embedded replica lease more than once, releasing a reference after the entry was already fully released, or double-dispose racing with another dispose while ReferenceCount is already zero.

Common situations: Double disposal of the same connection (e.g. using-block plus explicit Dispose or finalizer path), copying a connection object and disposing both copies, a bug in custom pooling code that calls release APIs directly.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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