{"record":{"id":"1b3e9b07e87cd716","repo":"microsoft/FASTER","slug":"this-method-can-only-be-used-with-a-read-only-fasterlog","errorCode":null,"errorMessage":"This method can only be used with a read-only FasterLog instance used for iteration. Set FasterLogSettings.ReadOnlyMode to true during creation to indicate this.","messagePattern":"This method can only be used with a read-only FasterLog instance used for iteration\\. Set FasterLogSettings\\.ReadOnlyMode to true during creation to indicate this\\.","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/FasterLog/FasterLog.cs","lineNumber":2209,"sourceCode":"            foreach (var item in _lastPersistedIterators)\n            {\n                if (info.Iterators.TryGetValue(item.Key, out var other))\n                {\n                    if (item.Value != other) return true;\n                }\n                else\n                    return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Synchronously recover instance to FasterLog's latest valid commit, when being used as a readonly log iterator\n        /// </summary>\n        public void RecoverReadOnly()\n        {\n            if (!readOnlyMode)\n                throw new FasterException(\"This method can only be used with a read-only FasterLog instance used for iteration. Set FasterLogSettings.ReadOnlyMode to true during creation to indicate this.\");\n\n            RestoreLatest(out _, out _);\n            SignalWaitingROIterators();\n        }\n\n        /// <summary>\n        /// Asynchronously recover instance to FasterLog's latest commit, when being used as a readonly log iterator\n        /// </summary>\n        public async ValueTask RecoverReadOnlyAsync(CancellationToken cancellationToken = default)\n        {\n            if (!readOnlyMode)\n                throw new FasterException(\"This method can only be used with a read-only FasterLog instance used for iteration. Set FasterLogSettings.ReadOnlyMode to true during creation to indicate this.\");\n\n            await RestoreLatestAsync(cancellationToken).ConfigureAwait(false);\n            SignalWaitingROIterators();\n        }\n\n        private void SignalWaitingROIterators()","sourceCodeStart":2191,"sourceCodeEnd":2227,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/FasterLog/FasterLog.cs#L2191-L2227","documentation":"RecoverReadOnly() synchronously advances a log instance to the latest valid commit, but this is only meaningful for instances created in read-only mode. FasterLog checks readOnlyMode at FasterLog.cs:2209 and throws if the instance is a normal (writable) log.","triggerScenarios":"Calling FasterLog.RecoverReadOnly() on an instance created without FasterLogSettings.ReadOnlyMode = true.","commonSituations":"Developers replicating the read-only replication pattern (a follower tailing a shared log device) forget to set ReadOnlyMode in settings, then call RecoverReadOnly in their polling loop; often after copying code from the read-only FasterLog sample.","solutions":["Set FasterLogSettings.ReadOnlyMode = true when constructing the instance used for iteration.","Use a separate read-only FasterLog instance for recovery/iteration instead of the writable producer instance.","On a writable log, recovery happens automatically at construction or via commit APIs; remove the RecoverReadOnly call."],"exampleFix":"// before\nvar log = new FasterLog(new FasterLogSettings { LogDevice = sharedDevice });\nlog.RecoverReadOnly();\n// after\nvar log = new FasterLog(new FasterLogSettings { LogDevice = sharedDevice, ReadOnlyMode = true });\nlog.RecoverReadOnly();","handlingStrategy":"validation","validationCode":"// caller-side guard\nif (!logSettings.ReadOnlyMode)\n    throw new InvalidOperationException(\"RecoverReadOnly requires FasterLogSettings.ReadOnlyMode = true\");","typeGuard":null,"tryCatchPattern":"try { log.RecoverReadOnly(); } catch (FasterException ex) when (ex.Message.Contains(\"read-only FasterLog instance\")) { /* use a read-only instance */ }","preventionTips":["Keep producer and consumer FasterLog instances separate with clearly named factories.","Only call RecoverReadOnly on instances obtained from a CreateReadOnly factory.","Document replication settings in one place to avoid dropping ReadOnlyMode."],"tags":["fasterlog","read-only","recovery","csharp"],"backgroundTag":"unsupported-operation","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"}