{"record":{"id":"04e5e354b2728e9f","repo":"microsoft/FASTER","slug":"cannot-commit-in-read-only-mode","errorCode":null,"errorMessage":"Cannot commit in read-only mode","messagePattern":"Cannot commit in read-only mode","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/FasterLog/FasterLog.cs","lineNumber":2704,"sourceCode":"                length = GetLength(ptr);\n\n                // forego checksum verification since record may not be read in full by AsyncGetHeaderOnlyFromDiskCallback()\n            }\n\n            record.Return();\n            return length;\n        }\n\n\n        private bool CommitInternal(out long commitTail, out long actualCommitNum, bool fastForwardAllowed, byte[] cookie, long proposedCommitNum, Action callback)\n        {\n            if (cannedException != null)\n                throw cannedException;\n\n            commitTail = actualCommitNum = 0;\n\n            if (readOnlyMode)\n                throw new FasterException(\"Cannot commit in read-only mode\");\n\n            if (fastForwardAllowed && (cookie != null || proposedCommitNum != -1 || callback != null))\n                throw new FasterException(\n                    \"Fast forwarding a commit is only allowed when no cookie, commit num, or callback is specified\");\n\n            var info = new FasterLogRecoveryInfo\n            {\n                FastForwardAllowed = fastForwardAllowed,\n                Cookie = cookie,\n                Callback = callback,\n            };\n            info.SnapshotIterators(PersistedIterators);\n            var commitRequired = ShouldCommmitMetadata(ref info) || (commitCoveredAddress < TailAddress);\n            // Only apply commit policy if not a strong commit\n            if (fastForwardAllowed && !commitPolicy.AdmitCommit(TailAddress, commitRequired))\n                return false;\n\n            // This critical section serializes commit record creation / commit content generation and ensures that the","sourceCodeStart":2686,"sourceCodeEnd":2722,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/FasterLog/FasterLog.cs#L2686-L2722","documentation":"FasterLog.CommitAsync (or Commit) was called on a FasterLog opened in read-only mode. A read-only log is typically attached for tailing/recovery on a replica and has no commit capability, so the library refuses the operation up front via this guard in FasterLog.cs:2704.","triggerScenarios":"Calling CommitAsync/Commit (including the fast-forward overload) on a FasterLog created with FastCommitMode or opened as a read-only subscriber/recover-only log where readOnlyMode is true.","commonSituations":"Opening a log on a backup node or with LogCommitManager pointing at an immutable snapshot, then reusing shared append code that unconditionally commits; connecting to a replicated log as a follower and calling the same enqueue-and-commit path as the primary.","solutions":["Check FasterLog.ReadOnlyMode (or how the instance was constructed) before calling any commit API and skip/branch the commit.","Open the log in writable mode on the node that owns the log (do not pass read-only/recovery-only settings).","On replicas, rely on log replication/checkpoint streaming from the primary instead of local commits.","Wrap shared append helpers so commit calls are conditional on writability."],"exampleFix":"// before\nawait log.CommitAsync();\n\n// after\nif (!log.ReadOnlyMode)\n    await log.CommitAsync();","handlingStrategy":"validation","validationCode":"if (log.ReadOnlyMode) throw new InvalidOperationException(\"This node cannot commit; log is read-only\");","typeGuard":null,"tryCatchPattern":"try { await log.CommitAsync(); } catch (FasterException ex) when (ex.Message == \"Cannot commit in read-only mode\") { /* route write to primary */ }","preventionTips":["Check ReadOnlyMode before any write path runs","Keep follower/replica code free of commit calls","Centralize append+commit behind a writability check"],"tags":["fasterlog","read-only","commit","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}