{"record":{"id":"93d5a89696be1d5a","repo":"elsa-workflows/elsa-core","slug":"lost-an-owner-context","errorCode":null,"errorMessage":"Lost an owner context","messagePattern":"Lost an owner context","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs","lineNumber":282,"sourceCode":"                existingActivityExecutionContext,\n                input,\n                activityWorkItemState.SchedulingActivityExecutionId,\n                activityWorkItemState.SchedulingWorkflowInstanceId,\n                activityWorkItemState.SchedulingCallStackDepth);\n            workflowExecutionContext.Scheduler.Schedule(workItem);\n        }\n    }\n\n    private static void ExtractCompletionCallbacks(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)\n    {\n        // Assert that all referenced owner contexts exist.\n        var activeContexts = workflowExecutionContext.GetActiveActivityExecutionContexts().ToList();\n        foreach (var completionCallback in workflowExecutionContext.CompletionCallbacks)\n        {\n            var ownerContext = activeContexts.FirstOrDefault(x => x == completionCallback.Owner);\n\n            if (ownerContext == null)\n                throw new(\"Lost an owner context\");\n        }\n\n        var completionCallbacks = workflowExecutionContext.CompletionCallbacks.Select(x => new CompletionCallbackState(x.Owner.Id, x.Child.NodeId, x.CompletionCallback?.Method.Name, x.Tag));\n\n        state.CompletionCallbacks = completionCallbacks.ToList();\n    }\n\n    private static void ExtractActiveActivityExecutionContexts(WorkflowState state, WorkflowExecutionContext workflowExecutionContext)\n    {\n        ActivityExecutionContextState CreateActivityExecutionContextState(ActivityExecutionContext activityExecutionContext)\n        {\n            var parentId = activityExecutionContext.ParentActivityExecutionContext?.Id;\n\n            if (parentId != null)\n            {\n                var parentContext = activityExecutionContext.WorkflowExecutionContext.ActivityExecutionContexts.FirstOrDefault(x => x.Id == parentId);\n\n                if (parentContext == null)","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Services/WorkflowStateExtractor.cs#L264-L300","documentation":"During workflow state extraction, WorkflowStateExtractor serializes all completion callbacks, each of which must reference an owner ActivityExecutionContext that is currently active. If a callback's owner is no longer among the active contexts, internal bookkeeping is inconsistent (the owner was completed/cleared without removing its callback), so the extractor throws rather than persisting corrupt state.","triggerScenarios":"Extract (persistence or suspension) while workflowExecutionContext.CompletionCallbacks contains a callback whose Owner is not in GetActiveActivityExecutionContexts() — i.e. an owner context completed or was removed but its child completion callback remained registered.","commonSituations":"A parent activity completed while children it scheduled were still pending (parent completed without awaiting all children); custom activities registering completion callbacks incorrectly; bugs in composite/parallel activity implementations; state extraction racing with context cleanup.","solutions":["Fix the parent activity to keep itself active until all scheduled children invoke their completion callbacks (use Complete() only after callbacks fire, or use ScheduleActivity with correct delegate/complete flags).","Ensure completion callbacks are removed when their owner context completes (clear callbacks in the owner's completion path).","Check custom activities for calls to Complete() before all child callbacks execute — use context.DeferCallbacks or wait for pending children.","Update Elsa: known parent-completion bugs in bundled activities have been fixed in newer versions.","If a third-party activity triggers it, report/replace it; workaround by restructuring the workflow so the parent remains active."],"exampleFix":"// before (custom parent activity)\nScheduleChildren(context);\ncontext.Complete(); // completes while children still pending -> lost owner context\n// after\nScheduleChildren(context);\ncontext.DeferCallbacks(); // keep context active until child completion callbacks run, then Complete()","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["state-extraction","completion-callbacks","csharp"],"backgroundTag":"internal-invariant-violation","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}