{"record":{"id":"2373da1b4d84ff7c","repo":"louthy/language-ext","slug":"transaction-not-running","errorCode":null,"errorMessage":"Transaction not running","messagePattern":"Transaction not running","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"LanguageExt.Core/Concurrency/STM/STM.cs","lineNumber":505,"sourceCode":"    /// <summary>\n    /// Conflict exception for internal use\n    /// </summary>\n    class ConflictException : Exception;\n\n    /// <summary>\n    /// Wraps a (A -> A) predicate as (object -> object)\n    /// </summary>\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    static Func<object, object> CastCommute<A>(Func<A, A> f) =>\n        obj => f((A)obj)!;\n\n    /// <summary>\n    /// Get the currently running TransactionId\n    /// </summary>\n    public static long TransactionId\n    {\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        get => transaction.Value?.transactionId ?? throw new InvalidOperationException(\"Transaction not running\");\n    }\n\n    /// <summary>\n    /// Transaction snapshot\n    /// </summary>\n    class Transaction\n    {\n        static long transactionIdNext;\n        public readonly long transactionId;\n        public TrieMap<EqLong, long, RefState> state;\n        public TrieMap<EqLong, long, Change<RefState>> changes;\n        public readonly System.Collections.Generic.HashSet<long> reads = new();\n        public readonly System.Collections.Generic.HashSet<long> writes = new();\n        public readonly System.Collections.Generic.List<(long Id, Func<object, object> Fun)> commutes = new();\n\n        public static readonly Transaction None = new (TrieMap<EqLong, long, RefState>.Empty);\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/louthy/language-ext/blob/2f0e3628242889774d4141960a35671a0280051f/LanguageExt.Core/Concurrency/STM/STM.cs#L487-L523","documentation":"`STM.TransactionId` is a static property returning the id of the currently running STM transaction. When no transaction is running on the current context, `transaction.Value` is null and the property throws `InvalidOperationException(\"Transaction not running\")` instead of returning a sentinel id. It is a contract that you only query transaction metadata from within `sync`/`atomic`.","triggerScenarios":"Reading `STM.TransactionId` from code outside any `STM.sync`/`atomic` block — e.g. logging helpers called after the transaction finished, or code executed on a different async context than the transaction.","commonSituations":"Diagnostics/logging inside helper methods that assume a transaction is active; async callbacks scheduled during the transaction that fire after it completes; custom Ref-like types querying the transaction id outside sync.","solutions":["Only read `STM.TransactionId` inside the `sync`/`atomic` delegate.","If the id is needed later, capture it into a local variable while the transaction is still running.","If you need a nullable check, avoid the property and design your API to pass the transaction state explicitly."],"exampleFix":"// before\nvar id = STM.TransactionId; // throws if no transaction\n\n// after\nSTM.sync(() =>\n{\n    var id = STM.TransactionId; // safe\n    return unit;\n});","handlingStrategy":"validation","validationCode":"// capture the id inside the transaction instead of reading it later\nlong id = STM.sync(() => { var i = STM.TransactionId; /* ... */ return i; });","typeGuard":null,"tryCatchPattern":"long? id = null;\ntry { id = STM.TransactionId; }\ncatch (InvalidOperationException) { /* no transaction running */ }","preventionTips":["Read STM.TransactionId only inside the sync/atomic delegate.","Pass transaction metadata explicitly to helpers rather than reading ambient state.","Capture the id early if it is needed after commit."],"tags":["stm","concurrency","transaction","csharp"],"backgroundTag":"invalid-state-transition","analyzedSha":"2f0e3628242889774d4141960a35671a0280051f","analyzedAt":"2026-09-15T03:31:55.716Z","contentChangedAt":"2026-09-15T03:31:55.716Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}