{"record":{"id":"1234094775473418","repo":"elsa-workflows/elsa-core","slug":"activity-context-is-not-a-flowchart","errorCode":null,"errorMessage":"Activity context is not a flowchart.","messagePattern":"Activity context is not a flowchart\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Core/Activities/Flowchart/Extensions/ActivityExecutionContextExtensions.cs","lineNumber":73,"sourceCode":"        {\n            return context.HasRunningActivityInstances()\n                   || context.HasScheduledWork()\n                   || context.HasUnconsumedTokens()\n                   || context.HasFaultedChildren();\n        }\n\n        public FlowGraph GetFlowGraph()\n        {\n            // Store in TransientProperties so FlowChart is not persisted in WorkflowState\n            var flowchart = (Activities.Flowchart)context.Activity;\n            var startActivity = flowchart.GetStartActivity(context.WorkflowExecutionContext.TriggerActivityId);\n            return context.TransientProperties.GetOrAdd(GraphTransientProperty, () => new FlowGraph(flowchart.Connections, startActivity));\n        }\n\n        public async Task CancelInboundAncestorsAsync(IActivity activity)\n        {\n            if(context.Activity is not Activities.Flowchart)\n                throw new InvalidOperationException(\"Activity context is not a flowchart.\");\n        \n            var flowGraph = context.GetFlowGraph();\n            var ancestorActivities = flowGraph.GetAncestorActivities(activity);\n            var inboundActivityExecutionContexts = context.WorkflowExecutionContext.ActivityExecutionContexts.Where(x => ancestorActivities.Contains(x.Activity) && x.ParentActivityExecutionContext == context).ToList();\n\n            // Cancel each ancestor activity.\n            foreach (var activityExecutionContext in inboundActivityExecutionContexts)\n            {\n                await activityExecutionContext.CancelActivityAsync();\n            }\n        }\n        \n        /// <summary>\n        /// Checks if the flowchart has any unconsumed tokens.\n        /// </summary>\n        public bool HasUnconsumedTokens()\n        {\n            var flowchart = (Activities.Flowchart)context.Activity;","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Extensions/ActivityExecutionContextExtensions.cs#L55-L91","documentation":"Thrown by CancelInboundAncestorsAsync when the ActivityExecutionContext's current activity is not a Flowchart. This extension method only works on a flowchart context because it needs the flow graph to compute which ancestor activities to cancel. It is an internal invariant check guarding misuse of the extension.","triggerScenarios":"Calling context.CancelInboundAncestorsAsync(activity) from an ActivityExecutionContext whose Activity is not an Activities.Flowchart — e.g. calling from a child activity of the flowchart or from a non-flowchart workflow root.","commonSituations":"Custom activities reusing flowchart-internal cancellation logic; refactors that move code out of the Flowchart handler into a shared helper without checking the enclosing activity type.","solutions":["Only call CancelInboundAncestorsAsync from code running on a Flowchart activity context.","Guard with a type check first: if (context.Activity is Activities.Flowchart) await context.CancelInboundAncestorsAsync(activity);","Use the Flowchart's own ActivityExecutionContext (the parent context), not a child activity's context.","For ancestor cancellation in non-flowchart containers, implement your own traversal instead of this flowchart-specific extension."],"exampleFix":"// before\nawait context.CancelInboundAncestorsAsync(activity); // throws when context.Activity is not a Flowchart\n// after\nif (context.Activity is Activities.Flowchart)\n    await context.CancelInboundAncestorsAsync(activity);","handlingStrategy":"type-guard","validationCode":"if (context.Activity is not Elsa.Workflows.Core.Activities.Flowchart)\n    throw new InvalidOperationException(\"CancelInboundAncestorsAsync requires a Flowchart context.\");\nawait context.CancelInboundAncestorsAsync(activity);","typeGuard":"static bool IsFlowchartContext(ActivityExecutionContext context) => context.Activity is Elsa.Workflows.Core.Activities.Flowchart;","tryCatchPattern":"try { await context.CancelInboundAncestorsAsync(activity); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Activity context is not a flowchart.\")\n{\n    logger.LogWarning(ex, \"Ancestor cancellation attempted on non-flowchart context {Type}\", context.Activity?.Type);\n}","preventionTips":["Only invoke flowchart-specific extensions from inside the Flowchart implementation.","Check context.Activity type before using flow graph APIs.","Keep flowchart-internal logic encapsulated instead of calling it from child activities."],"tags":["workflow","flowchart","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}