elsa-workflows/elsa-core · error · FaultException
AlterationFaultCodes.PlanNotFound
AlterationFaultCodes.PlanNotFound
Error message
Alteration Plan with ID {planId} not found. What it means
The GenerateAlterations activity's GetPlanAsync looked up an AlterationPlan by ID via IAlterationPlanStore.FindAsync and found nothing. It then throws a FaultException with AlterationFaultCodes.PlanNotFound, which surfaces as a workflow fault rather than a plain exception. This guards the alteration pipeline against running with a missing or already-deleted plan.
Solutions
- Verify the planId exists before scheduling the workflow by querying the alteration plan store (or API) for that ID.
- Check that the workflow is running against the same persistence store/environment where the plan was created.
- Confirm the plan was not removed by cleanup or a prior workflow run; re-create it if needed.
- Catch FaultException with code AlterationFaultCodes.PlanNotFound in the workflow's fault handler and surface a user-friendly message.
Example fix
// before
await workflowInput.Set("PlanId", copiedGuidString);
// after
var plan = await alterationPlanStore.FindAsync(new AlterationPlanFilter { Id = planId });
if (plan == null)
throw new InvalidOperationException($"Plan {planId} does not exist; create it before running GenerateAlterations."); Defensive patterns
Strategy: validation
Validate before calling
var plan = await alterationPlanStore.FindAsync(new AlterationPlanFilter { Id = planId });
if (plan == null)
throw new InvalidOperationException($"Plan {planId} not found; aborting before scheduling alteration workflow."); Try / catch
try
{
await generateAlterationsActivity.ExecuteAsync(context);
}
catch (FaultException ex) when (ex.FaultCode == AlterationFaultCodes.PlanNotFound)
{
logger.LogWarning("Alteration plan {PlanId} not found", planId);
} Prevention
- Always create the plan first and use the ID returned by the store, not a manually typed one.
- Keep plans and workflows on the same environment/persistence store.
- Add a pre-flight existence check when accepting plan IDs as workflow input.
When it happens
Trigger: Calling GenerateAlterations (or otherwise executing GetPlanAsync) with a planId for which IAlterationPlanStore.FindAsync(planFilter) returns null — i.e., the ID does not exist in the plan store.
Common situations: Passing a hardcoded or copied plan ID that was never created; the plan was deleted by retention/cleanup before the workflow ran; using an ID from a different database/environment (staging vs production); a typo or GUID casing/whitespace issue in workflow input.
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
- No alterations found in the transient properties.
- No alteration log found in the transient properties.
- {fault.Code}
- FaultException raised by Fault activity
- Activity type not found
AI-assisted analysis of elsa-workflows/elsa-core@fe9217bdfa (2026-09-13).
Data as JSON: /api/errors/4e211f54070ef88f.
Report an issue: GitHub.
Appendix: source
Thrown at src/modules/Elsa.Alterations/Activities/GenerateAlterationJobs.cs:66
if (workflowInstanceIds.Any())
await GenerateJobsAsync(context, plan, workflowInstanceIds);
context.SetResult(workflowInstanceIds.Count);
}
private async Task<AlterationPlan> GetPlanAsync(ActivityExecutionContext context)
{
var cancellationToken = context.CancellationToken;
var planId = context.Get(PlanId)!;
var alterationPlanStore = context.GetRequiredService<IAlterationPlanStore>();
var planFilter = new AlterationPlanFilter
{
Id = planId
};
var plan = await alterationPlanStore.FindAsync(planFilter, cancellationToken);
if (plan == null)
throw new FaultException(AlterationFaultCodes.PlanNotFound, AlterationFaultCategories.Alteration, DefaultFaultTypes.System, $"Alteration Plan with ID {planId} not found.");
return plan;
}
private async Task UpdatePlanStatusAsync(ActivityExecutionContext context, AlterationPlan plan)
{
var cancellationToken = context.CancellationToken;
var alterationPlanStore = context.GetRequiredService<IAlterationPlanStore>();
plan.Status = AlterationPlanStatus.Generating;
await alterationPlanStore.SaveAsync(plan, cancellationToken);
}
private async Task<IEnumerable<string>> FindMatchingWorkflowInstanceIdsAsync(ActivityExecutionContext context, AlterationWorkflowInstanceFilter filter)
{
var cancellationToken = context.CancellationToken;
var workflowInstanceFinder = context.GetRequiredService<IWorkflowInstanceFinder>();
return await workflowInstanceFinder.FindAsync(filter, cancellationToken);
}View on GitHub (pinned to fe9217bdfa)