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
- 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.
- Check workflowType.Activities and IsStart flags in code before calling RestartWorkflowAsync and refuse to call it when no start activity exists.
- If the definition is corrupted, recreate or re-import the workflow type from a known-good recipe/export.
- 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
- Never delete the start event from a workflow type without replacing it first
- Validate workflow type definitions (one IsStart activity) before saving or importing
- Add a pre-restart check for a start activity in custom admin actions
- Re-export/recreate corrupted workflow types from known-good recipes
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
- Unknown XmlRpc value type
- The content item is missing a 'ContentItemId'.
- The 'CreateContentTask' can't update the content item as it…
- The 'CreateContentTask' can't create the content item as it…
- The 'CreateContentTask' can't publish the content item as…
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)