tursodatabase/turso · error · InvalidOperationException

Turso sync connection ownership is unbalanced.

Error message

Turso sync connection ownership is unbalanced.

What it means

TursoSyncDatabase tracks connection ownership with an atomic counter (_activeConnections). ReleaseConnection() decrements it and throws InvalidOperationException if the count would go negative, which indicates a bug: a Release without a matching Connect — an internal bookkeeping invariant violation rather than a user configuration problem.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoSyncDatabase.cs:315

                    TursoSyncOperationKind.Connect,
                    cancellationToken)
                .ConfigureAwait(false);
            EnsureResultKind(operation, TursoSyncOperationResultKind.Connection);
            var connectionHandle = TursoSyncBindings.ExtractConnection(_handle, operation);
            Interlocked.Increment(ref _activeConnections);
            return connectionHandle;
        }
        finally
        {
            _operationLock.Release();
        }
    }

    internal void ReleaseConnection()
    {
        var remaining = Interlocked.Decrement(ref _activeConnections);
        if (remaining < 0)
            throw new InvalidOperationException("Turso sync connection ownership is unbalanced.");
        if (remaining == 0 && Volatile.Read(ref _disposeRequested) != 0)
            DisposeResources();
    }

    private async Task RunVoidOperationAsync(
        Func<TursoSyncDatabaseHandle, TursoSyncOperationHandle> start,
        TursoSyncOperationKind operationKind,
        CancellationToken cancellationToken)
    {
        ThrowIfDisposed();
        await _operationLock.WaitAsync(cancellationToken).ConfigureAwait(false);
        try
        {
            ThrowIfDisposed();
            using var operation = StartOperation(start, operationKind);
            await DriveOperationAsync(operation, operationKind, cancellationToken).ConfigureAwait(false);
            EnsureResultKind(operation, TursoSyncOperationResultKind.None);
        }

View on GitHub (pinned to 6c72522679)

Solutions

  1. Check custom code for duplicate ReleaseConnection() calls or calling it without a prior successful Connect.
  2. Ensure Dispose is not racing concurrent Connect/Release calls; serialize disposal with connection lifecycle.
  3. If reproducible, report as a driver bug with a stack trace — this is an internal invariant violation.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    connection.Close();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("ownership is unbalanced"))
{
    _logger.LogError(ex, "Driver bug: unbalanced connection ownership. Report with stack trace.");
}

Prevention

When it happens

Trigger: ReleaseConnection() called (via ConnectAsync's cleanup path) more times than ConnectAsync succeeded incrementing _activeConnections — e.g. double-release on a failure path or releasing after disposal raced the connect.

Common situations: Races between connection close/dispose and concurrent connect attempts; calling internal release APIs from custom wrapper code around TursoSyncDatabase.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-31). Data as JSON: /api/errors/1c9b6a6d119edea3. Report an issue: GitHub.