elsa-workflows/elsa-core · error · InvalidOperationException

ActivityExecutionContext not found. This value exists only…

Error message

ActivityExecutionContext not found. This value exists only on activity execution contexts.

What it means

An InvalidOperationException thrown by GetActivityExecutionContext when the ExpressionExecutionContext's TransientProperties does not contain the ActivityExecutionContext key. Like the workflow-level variant, the ActivityExecutionContext is only attached during activity-scoped expression evaluation.

Solutions

  1. Ensure the expression is evaluated during activity execution so the key is registered in TransientProperties.
  2. Use TryGetActivityExecutionContext(out var ctx) instead of throwing when absence is acceptable.
  3. Pass the ActivityExecutionContext explicitly to the consuming code.
  4. In tests, seed TransientProperties[ActivityExecutionContextKey] with a stub context.

Example fix

// before
var activityExecutionContext = context.GetActivityExecutionContext(); // throws

// after
if (context.TryGetActivityExecutionContext(out var activityExecutionContext))
{
    // use activityExecutionContext
}
Defensive patterns

Strategy: type-guard

Validate before calling

var hasActivityContext = expressionContext.TransientProperties.ContainsKey(ActivityExecutionContextKey);

Type guard

bool TryGetActivityContext(ExpressionExecutionContext ctx, out ActivityExecutionContext? actCtx)
    => ctx.TransientProperties.TryGetValue(ActivityExecutionContextKey, out var v) && (actCtx = v as ActivityExecutionContext) is not null;

Try / catch

catch (InvalidOperationException ex) when (ex.Message.StartsWith("ActivityExecutionContext not found"))
{
    // expression was evaluated outside an activity; handle design-time case
}

Prevention

When it happens

Trigger: Calling GetActivityExecutionContext() on an ExpressionExecutionContext built without an activity execution - e.g., evaluating expressions in a designer/preview, workflow-level variables, background re-evaluation, or tests constructing ExpressionExecutionContext manually without the key.

Common situations: Expression evaluated by a custom evaluator that bypasses the activity pipeline; expressions evaluated against workflow variables only; unit tests building ExpressionExecutionContexts with only memory registers.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13). Data as JSON: /api/errors/c458353ff47afd36. Report an issue: GitHub.

Appendix: source

Thrown at src/modules/Elsa.Workflows.Core/Extensions/ExpressionExecutionContextExtensions.cs:92

        /// <summary>
        /// Returns the <see cref="WorkflowExecutionContext"/> of the specified <see cref="ExpressionExecutionContext"/>
        /// </summary>
        public WorkflowExecutionContext GetWorkflowExecutionContext()
        {
            return context.TransientProperties.TryGetValue(WorkflowExecutionContextKey, out var value)
                ? (WorkflowExecutionContext)value
                : throw new InvalidOperationException("WorkflowExecutionContext not found. This value exists only on activity execution contexts.");
        }

        /// <summary>
        /// Returns the <see cref="ActivityExecutionContext"/> of the specified <see cref="ExpressionExecutionContext"/>
        /// </summary>
        public ActivityExecutionContext GetActivityExecutionContext()
        {
            return context.TransientProperties.TryGetValue(ActivityExecutionContextKey, out var value)
                ? (ActivityExecutionContext)value
                : throw new InvalidOperationException("ActivityExecutionContext not found. This value exists only on activity execution contexts.");
        }

        /// <summary>
        /// Returns the <see cref="ActivityExecutionContext"/> of the specified <see cref="ExpressionExecutionContext"/>
        /// </summary>
        public bool TryGetActivityExecutionContext(out ActivityExecutionContext activityExecutionContext) => context.TransientProperties.TryGetValue(ActivityExecutionContextKey, out activityExecutionContext!);

        /// <summary>
        /// Returns the <see cref="Activity"/> of the specified <see cref="ExpressionExecutionContext"/>
        /// </summary>
        public IActivity GetActivity() => (IActivity)context.TransientProperties[ActivityKey];

        /// <summary>
        /// Returns the value of the specified input.
        /// </summary>
        public T? Get<T>(Input<T>? input) => input != null ? context.GetBlock(input.MemoryBlockReference).Value.ConvertTo<T>() : default;

        /// <summary>

View on GitHub (pinned to fe9217bdfa)