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

  1. Register the activity type with the workflow runtime (implement IActivityProvider / feature module that installs the descriptor).
  2. Verify the activity's Type string matches the registered descriptor's Type exactly (case-sensitive).
  3. Ensure the NuGet package / assembly containing the activity is referenced and its feature is installed.
  4. 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

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


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)