OrchardCMS/OrchardCore · error · InvalidOperationException

Workflow with ID does not have a start activity.

Error message

Workflow with ID {workflowType.Id} does not have a start activity.

What it means

RestartWorkflowAsync starts a NEW workflow instance of the given type and must begin execution at the type's designated start activity. The method requires workflowType.Activities to contain an activity with IsStart == true; if none exists it throws InvalidOperationException, because a restarted workflow has no entry point and could never run.

Solutions

  1. Open the workflow type definition in the admin UI and re-add a start activity (an event such as a signal/trigger) so exactly one activity has IsStart = true, then retry the restart.
  2. Check workflowType.Activities and IsStart flags in code before calling RestartWorkflowAsync and refuse to call it when no start activity exists.
  3. If the definition is corrupted, recreate or re-import the workflow type from a known-good recipe/export.
  4. If activities exist but IsStart is false due to a storage/import bug, patch the stored WorkflowType document to mark the intended start activity.

Example fix

// before
var wfType = await workflowTypeStore.GetAsync(id);
await workflowManager.RestartWorkflowAsync(wfType); // throws if no IsStart activity
// after
var wfType = await workflowTypeStore.GetAsync(id);
if (wfType?.Activities?.Any(a => a.IsStart) == true)
{
    await workflowManager.RestartWorkflowAsync(wfType);
}
Defensive patterns

Strategy: validation

Validate before calling

// before restart
ArgumentNullException.ThrowIfNull(workflowType);
if (workflowType.Activities?.Any(a => a.IsStart) != true)
    throw new InvalidOperationException($"Workflow type '{workflowType.Id}' has no start activity; cannot restart.");

Type guard

static bool HasStartActivity(WorkflowType t) => t?.Activities?.Any(a => a.IsStart) == true;

Try / catch

try { await workflowManager.RestartWorkflowAsync(workflowType, input, correlationId); }
catch (InvalidOperationException ex) when (ex.Message.Contains("does not have a start activity"))
{ logger.LogError(ex, "Workflow type {Id} lacks a start activity", workflowType.Id); /* notify admin to fix definition */ }

Prevention

When it happens

Trigger: Calling IWorkflowManager.RestartWorkflowAsync (directly or via the workflow restart admin/API path) for a workflow type whose activity list is empty or whose activities all have IsStart == false — e.g. the start activity was deleted in the editor, the workflow type definition was saved in a broken state, or activities were not loaded from storage.

Common situations: Admin 'Restart' action on a workflow type whose start event (e.g. a SignalEvent or trigger) was removed; corrupted or partially imported workflow type definitions; a bug in custom code that clears the Activities collection before calling RestartWorkflowAsync; deserialization where IsStart flags were lost.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/12c84f0f7c54b3a9. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Workflows/Services/WorkflowManager.cs:299

        if (workflowContext.Status == WorkflowStatus.Finished && workflowType.DeleteFinishedWorkflows)
        {
            await _workflowStore.DeleteAsync(workflowContext.Workflow);
        }
        else
        {
            await PersistAsync(workflowContext);
        }

        return workflowContext;
    }

    public async Task<WorkflowExecutionContext> RestartWorkflowAsync(WorkflowType workflowType, IDictionary<string, object> input = null, string correlationId = null)
    {
        ArgumentNullException.ThrowIfNull(workflowType);

        var startActivity = workflowType.Activities?.FirstOrDefault(x => x.IsStart)
            ?? throw new InvalidOperationException($"Workflow with ID {workflowType.Id} does not have a start activity.");

        // Create a new workflow instance.
        var workflow = NewWorkflow(workflowType, correlationId);

        // Create a workflow context.
        var workflowContext = await CreateWorkflowExecutionContextAsync(workflowType, workflow, input);
        workflowContext.Status = WorkflowStatus.Starting;

        // Signal every activity that the workflow is about to start.
        // This should be called prior OnInputReceivedAsync.
        await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnWorkflowRestartingAsync(workflowContext, workflowContext.CancellationToken));

        // Signal every activity about available input.
        await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnInputReceivedAsync(workflowContext, input));

        if (workflowContext.CancellationToken.IsCancellationRequested)
        {
            return workflowContext;

View on GitHub (pinned to 4306c0717f)