elsa-workflows/elsa-core · error · ActivityNotFoundException
Activity type not found
Error message
Activity type not found
What it means
An ActivityNotFoundException raised while creating an ActivityExecutionContext because ActivityRegistryLookup.FindAsync could not resolve the activity's Type to a registered activity descriptor. Every activity instance must map to a descriptor registered in the ActivityRegistry.
Solutions
- Register the activity type with the workflow runtime (implement IActivityProvider / feature module that installs the descriptor).
- Verify the activity's Type string matches the registered descriptor's Type exactly (case-sensitive).
- Ensure the NuGet package / assembly containing the activity is referenced and its feature is installed.
- Check for type renames after upgrades and update persisted workflow definitions accordingly.
Example fix
// before
// Custom MyActivity used in workflow but never registered -> ActivityNotFoundException
// after
public class MyActivityFeature : IFeature
{
public void Apply() => Module.AddActivity<MyActivity>();
}
// or via services.AddActivity<MyActivity>(); in host setup Defensive patterns
Strategy: validation
Validate before calling
// at host startup, assert all workflow activity types are registered
var lookup = services.GetRequiredService<IActivityRegistryLookupService>();
foreach (var type in usedActivityTypes)
if (await lookup.FindAsync(type) is null)
throw new InvalidOperationException($"Activity type '{type}' is not registered. Install its feature."); Try / catch
// catch Elsa.Workflows.Core.Exceptions.ActivityNotFoundException
catch (ActivityNotFoundException ex)
{
logger.LogError(ex, "Unregistered activity type {Type}; install the owning module/feature.", ex.ActivityType);
} Prevention
- Install every module/feature whose activities your workflows use.
- Add a startup smoke test that loads all workflow definitions.
- After package upgrades, verify activity Type strings in persisted workflows still resolve.
When it happens
Trigger: Calling WorkflowExecutionContext.CreateActivityExecutionContextAsync with an IActivity whose Type string does not match any registered activity type - typically custom activities not registered via a feature/module, or activities from assemblies not loaded.
Common situations: Custom activity class added to a workflow but its module/feature was not installed on the host; typo or renamed activity type; deserialized workflow JSON referencing an activity type from a package no longer referenced; missing AddActivity/InstallFeatures registration.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Activity descriptor not found
- Output conversion failed during result validation
- No input with name could be found
- WorkflowExecutionContext not found. This value exists only…
- Activity not found.
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/c96119e6f89f4ae1.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Workflows.Core/Contexts/WorkflowExecutionContext.cs:583
throw new($"Cannot transition from {SubStatus} to {subStatus}");
SubStatus = subStatus;
UpdatedAt = SystemClock.UtcNow;
if (Status == WorkflowStatus.Finished)
FinishedAt = UpdatedAt;
if (Status == WorkflowStatus.Finished || SubStatus == WorkflowSubStatus.Suspended)
{
foreach (var registration in _cancellationRegistrations)
registration.Dispose();
}
}
/// Creates a new <see cref="ActivityExecutionContext"/> for the specified activity.
public async Task<ActivityExecutionContext> CreateActivityExecutionContextAsync(IActivity activity, ActivityInvocationOptions? options = null)
{
var activityDescriptor = await ActivityRegistryLookup.FindAsync(activity) ?? throw new ActivityNotFoundException(activity.Type);
var tag = options?.Tag;
var parentContext = options?.Owner;
var now = SystemClock.UtcNow;
var id = IdentityGenerator.GenerateId();
var activityExecutionContext = new ActivityExecutionContext(id, this, parentContext, activity, activityDescriptor, now, tag, SystemClock, CancellationToken);
var variablesToDeclare = options?.Variables ?? [];
var variableContainer = new[]
{
activityExecutionContext.ActivityNode
}.Concat(activityExecutionContext.ActivityNode.Ancestors()).FirstOrDefault(x => x.Activity is IVariableContainer)?.Activity as IVariableContainer;
activityExecutionContext.ExpressionExecutionContext.TransientProperties[ExpressionExecutionContextExtensions.ActivityExecutionContextKey] = activityExecutionContext;
if (variableContainer != null)
{
foreach (var variable in variablesToDeclare)
{
// Declare a dynamic variable on the activity execution context.
activityExecutionContext.DynamicVariables.RemoveWhere(x => x.Name == variable.Name);View on GitHub (pinned to fe9217bdfa)