{"record":{"id":"5d3c4c085b17a13a","repo":"tursodatabase/turso","slug":"turso-sync-operations-cannot-be-reentered-from-the","errorCode":null,"errorMessage":"Turso sync operations cannot be reentered from the sync HTTP handler.","messagePattern":"Turso sync operations cannot be reentered from the sync HTTP handler\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoSyncDatabase.cs","lineNumber":274,"sourceCode":"    {\n        using var item = TursoSyncBindings.TakeIoItem(_handle);\n        if (item is not null)\n            RunSynchronously(() => HandleIoItemAsync(item, CancellationToken.None));\n        TursoSyncBindings.StepIoCallbacks(_handle);\n    }\n\n    internal IDisposable EnterConnectionOperation()\n    {\n        ThrowIfIoReentrant();\n        ObjectDisposedException.ThrowIf(Volatile.Read(ref _resourcesDisposed) != 0, this);\n        _operationLock.Wait();\n        return new ConnectionOperationLease(_operationLock);\n    }\n\n    internal void ThrowIfIoReentrant()\n    {\n        if (_ioCallbackDepth.Value != 0)\n            throw new InvalidOperationException(\"Turso sync operations cannot be reentered from the sync HTTP handler.\");\n    }\n\n    internal async Task<TursoDatabaseHandle> ConnectHandleAsync(CancellationToken cancellationToken)\n    {\n        ThrowIfDisposed();\n        await _operationLock.WaitAsync(cancellationToken).ConfigureAwait(false);\n        try\n        {\n            ThrowIfDisposed();\n            using var operation = StartOperation(\n                TursoSyncBindings.StartConnect,\n                TursoSyncOperationKind.Connect);\n            await DriveOperationAsync(\n                    operation,\n                    TursoSyncOperationKind.Connect,\n                    cancellationToken)\n                .ConfigureAwait(false);\n            EnsureResultKind(operation, TursoSyncOperationResultKind.Connection);","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/tursodatabase/turso/blob/c1e59287258d99b309e362a63f48822256e2f65f/bindings/dotnet/src/Turso.Data/TursoSyncDatabase.cs#L256-L292","documentation":"TursoSyncDatabase serializes operations on a connection and forbids reentrancy: code running inside the sync HTTP I/O callback (the driver's own HTTP handler serving the embedded replica's local HTTP endpoint) must not start new sync/connection operations. ThrowIfIoReentrant() throws InvalidOperationException when the I/O callback depth is non-zero and a new operation is attempted, preventing deadlocks and state corruption.","triggerScenarios":"Calling SyncAsync, Dispose, EnterConnectionOperation, or any connection operation from within code that itself runs while the sync HTTP handler is servicing a request (ioCallbackDepth > 0) — e.g. a custom handler or app code invoked during HTTP handling that touches the same TursoSyncDatabase.","commonSituations":"Application code hooked into the sync HTTP pipeline (logging, auth callbacks) that reuses the connection; nested sync calls triggered indirectly while a sync is in flight.","solutions":["Move any work that calls SyncAsync/other sync operations out of the HTTP handler callback; queue it and execute after the callback returns.","Use a separate TursoSyncDatabase/TursoConnection instance inside the handler if independent access is required.","Guard shared call sites with a check/flag so they skip reentrant calls during an active sync."],"exampleFix":"// before (inside handler invoked during sync)\nawait syncDatabase.SyncAsync();\n// after\n_syncPending = true; // handle after callback completes","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await connection.SyncAsync(ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"reentered\"))\n{\n    _logger.LogWarning(\"Sync reentered from HTTP handler; deferring.\");\n    _deferredSync = true;\n}","preventionTips":["Never call sync/connection APIs from code executing inside the sync HTTP handler.","Queue handler-triggered work and run it after the callback completes.","Use separate TursoSyncDatabase instances for handler-side needs."],"tags":["dotnet","reentrancy","sync","concurrency"],"backgroundTag":"sync-operation-reentrancy","analyzedSha":"c1e59287258d99b309e362a63f48822256e2f65f","analyzedAt":"2026-08-31T11:17:35.598Z","contentChangedAt":"2026-08-31T11:17:35.598Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}