{"record":{"id":"abca8356d09fc48a","repo":"litedb-org/LiteDB","slug":"0-abca83","errorCode":"0","errorMessage":"There is no more active transaction for this cursor: {_cursor.Query.ToSQL(_cursor.Collection)}","messagePattern":"There is no more active transaction for this cursor: (.+?)","errorType":"exception","errorClass":"LiteException","httpStatus":null,"severity":"error","filePath":"LiteDB/Engine/Query/QueryExecutor.cs","lineNumber":149,"sourceCode":"\n                    try\n                    {\n                        read = enumerator.MoveNext();\n                    }\n                    catch (Exception ex)\n                    {\n                        _state.Handle(ex);\n                        throw ex;\n                    }\n\n                    while (read)\n                    {\n                        _cursor.Fetched++;\n                        _cursor.Elapsed.Stop();\n\n                        yield return enumerator.Current;\n\n                        if (transaction.State != TransactionState.Active) throw new LiteException(0, $\"There is no more active transaction for this cursor: {_cursor.Query.ToSQL(_cursor.Collection)}\");\n\n                        _cursor.Elapsed.Start();\n\n                        try\n                        {\n                            read = enumerator.MoveNext();\n                        }\n                        catch (Exception ex)\n                        {\n                            _state.Handle(ex);\n                            throw ex;\n                        }\n                    }\n                }\n            };\n        }\n\n        /// <summary>","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/litedb-org/LiteDB/blob/f906a5f850678719e39a39a006cb66dcae563cfa/LiteDB/Engine/Query/QueryExecutor.cs#L131-L167","documentation":"Thrown during cursor iteration in QueryExecutor when the transaction backing the cursor is no longer in the Active state between yielding documents. This typically means the transaction was committed, rolled back, or disposed while the cursor (BsonDataReader) was still open and being enumerated. The engine checks transaction.State != Active after each yielded document and aborts to prevent reading from a dead snapshot.","triggerScenarios":"Opening a reader from db.Execute/Query, then calling db.Commit(), db.Rollback(), or disposing the LiteDatabase/engine before fully iterating the reader. Also occurs if the transaction monitor evicts/times out the transaction mid-cursor due to lock timeout or Safepoint abort.","commonSituations":"Returning a lazy BsonDataReader from a using-block scope and enumerating it after disposal; committing inside a foreach over a query result; long-running cursor that exceeds the lock timeout; nested transactions or auto-commit interfering.","solutions":["Fully enumerate and dispose the reader before committing, rolling back, or disposing the database.","Materialize results (ToList/ToArray) if the reader must outlive the transaction.","Avoid mixing explicit Commit/Rollback with an open reader on the same thread.","Increase the TIMEOUT pragma if the cursor legitimately runs long, or paginate."],"exampleFix":"// before — reader iterated after dispose/commit\nIEnumerable<BsonDocument> GetDocs()\n{\n    using var db = new LiteDatabase(\"data.db\");\n    var reader = db.Execute(\"SELECT $ FROM items\");\n    while (reader.Read()) yield return reader.Current.AsDocument;\n} // db disposed while lazy yield still active -> throws\n\n// after — materialize before dispose\nList<BsonDocument> GetDocs()\n{\n    using var db = new LiteDatabase(\"data.db\");\n    var result = new List<BsonDocument>();\n    using var reader = db.Execute(\"SELECT $ FROM items\");\n    while (reader.Read()) result.Add(reader.Current.AsDocument);\n    return result;\n}","handlingStrategy":"validation","validationCode":"public List<BsonDocument> SafeQuery(LiteDatabase db, string sql)\n{\n    var result = new List<BsonDocument>();\n    using (var reader = db.Execute(sql))\n    {\n        while (reader.Read())\n            result.Add(reader.Current.AsDocument);\n    } // reader disposed before db goes out of scope\n    return result;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    foreach (var doc in LazyQuery(db)) { /* ... */ }\n}\ncatch (LiteException ex) when (ex.Message.Contains(\"no more active transaction\"))\n{\n    // The reader outlived its transaction. Materialize results earlier and retry.\n    throw new InvalidOperationException(\"Reader was enumerated after its transaction ended. Call ToList() before the transaction closes.\", ex);\n}","preventionTips":["Fully enumerate and dispose readers before committing or disposing the DB.","Never return a lazy BsonDataReader from a scope that will be disposed.","Materialize with ToList()/ToArray() if results must outlive the transaction.","Keep reader lifetimes strictly shorter than the transaction."],"tags":["query","cursor","transaction","concurrency","litedb-engine"],"backgroundTag":null,"analyzedSha":"f906a5f850678719e39a39a006cb66dcae563cfa","analyzedAt":"2026-08-13T21:56:30.148Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}