{"record":{"id":"e49f4da840062914","repo":"microsoft/FASTER","slug":"unexpected-operationtype","errorCode":null,"errorMessage":"Unexpected OperationType","messagePattern":"Unexpected OperationType","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/Index/FASTER/FASTERThread.cs","lineNumber":220,"sourceCode":"        internal Status InternalCompletePendingRequestFromContext<Input, Output, Context, FasterSession>(FasterSession fasterSession, AsyncIOContext<Key, Value> request,\n                                                                    ref PendingContext<Input, Output, Context> pendingContext, out AsyncIOContext<Key, Value> newRequest)\n            where FasterSession : IFasterSession<Key, Value, Input, Output, Context>\n        {\n            Debug.Assert(epoch.ThisInstanceProtected(), \"InternalCompletePendingRequestFromContext requires epoch acquision\");\n            newRequest = default;\n\n            // If NoKey, we do not have the key in the initial call and must use the key from the satisfied request.\n            // With the new overload of CompletePending that returns CompletedOutputs, pendingContext must have the key.\n            if (pendingContext.NoKey && pendingContext.key == default)\n                pendingContext.key = hlog.GetKeyContainer(ref hlog.GetContextRecordKey(ref request));\n            ref Key key = ref pendingContext.key.Get();\n\n            OperationStatus internalStatus = pendingContext.type switch\n            {\n                OperationType.READ => ContinuePendingRead(request, ref pendingContext, fasterSession),\n                OperationType.RMW => ContinuePendingRMW(request, ref pendingContext, fasterSession),\n                OperationType.CONDITIONAL_INSERT => ContinuePendingConditionalCopyToTail(request, ref pendingContext, fasterSession),\n                _ => throw new FasterException(\"Unexpected OperationType\")\n            };\n\n            var status = HandleOperationStatus(fasterSession.Ctx, ref pendingContext, internalStatus, out newRequest);\n\n            // If done, callback user code\n            if (status.IsCompletedSuccessfully)\n            {\n                if (pendingContext.type == OperationType.READ)\n                {\n                    fasterSession.ReadCompletionCallback(ref key,\n                                                     ref pendingContext.input.Get(),\n                                                     ref pendingContext.output,\n                                                     pendingContext.userContext,\n                                                     status,\n                                                     new RecordMetadata(pendingContext.recordInfo, pendingContext.logicalAddress));\n                }\n                else\n                {","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/Index/FASTER/FASTERThread.cs#L202-L238","documentation":"When FASTER resumes a pending operation during InternalCompletePendingRequestFromContext, it switches on pendingContext.type (READ, RMW, CONDITIONAL_INSERT). Any other OperationType reaching this code path means internal bookkeeping is corrupt, so the library throws FasterException as an invariant failure rather than continuing. User code almost never causes this directly; it indicates a bug or corrupted pending-context state.","triggerScenarios":"Calling status/CompletePending paths while a pending context holds an unexpected operation type (e.g. OperationType.UPSERT or NONE stored in pendingContext), typically from an internal state bug, mixed-session misuse, or memory corruption.","commonSituations":"Debugging after a crash-recovery resume, using Unsafe for odd record sizes with a mismatched session, or running a version with a known FASTER bug in pending-request continuation.","solutions":["Capture the pendingContext.type value and file/reproduce as a FASTER bug; this is not a user-recoverable condition.","Update to the latest FASTER build; several pending-operation continuation bugs have been fixed upstream.","Avoid sharing pending contexts across sessions/threads and ensure every StartRequest context is created by the same session that completes it."],"exampleFix":"// before\n// completing a request whose context was built by another session\notherCtx.pendingContext = myCtx.pendingContext;\nsession.CompletePending(false);\n// after\n// let each session own and complete its own pending contexts\nmyCtx.session.CompletePending(false);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { session.CompletePendingWithOutputs(out completed, wait: true); }\ncatch (FasterException ex) when (ex.Message == \"Unexpected OperationType\")\n{ logger.LogCritical(ex, \"FASTER internal invariant failure: corrupt pending context\"); throw; }","preventionTips":["Never share or transfer pending contexts between sessions or threads.","Keep FASTER package updated to pick up pending-request continuation bug fixes.","Minimize use of exotic paths (UnsafeMode, mixed sync/async on one session) that stress the continuation switch."],"tags":["faster","internal-invariant","pending-operations","csharp"],"backgroundTag":"internal-invariant-violation","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}