{"record":{"id":"3c3af258e2b491be","repo":"elsa-workflows/elsa-core","slug":"alterationfaultcodes-plannotfound-alteration-plan-with-id","errorCode":"AlterationFaultCodes.PlanNotFound","errorMessage":"Alteration Plan with ID {planId} not found.","messagePattern":"Alteration Plan with ID (.+?) not found\\.","errorType":"error_code","errorClass":"FaultException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Alterations/Activities/DispatchAlterationJobs.cs","lineNumber":50,"sourceCode":"    /// <summary>\n    /// The ID of the alteration plan.\n    /// </summary>\n    public Input<string> PlanId { get; set; } = null!;\n\n    /// <inheritdoc />\n    protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)\n    {\n        var cancellationToken = context.CancellationToken;\n        var planId = context.Get(PlanId)!;\n        var alterationPlanStore = context.GetRequiredService<IAlterationPlanStore>();\n        var planFilter = new AlterationPlanFilter\n        {\n            Id = planId\n        };\n        var plan = await alterationPlanStore.FindAsync(planFilter, cancellationToken);\n\n        if (plan == null)\n            throw new FaultException(AlterationFaultCodes.PlanNotFound, AlterationFaultCategories.Alteration, DefaultFaultTypes.System, $\"Alteration Plan with ID {planId} not found.\");\n\n        // Update status.\n        plan.Status = AlterationPlanStatus.Dispatching;\n        await alterationPlanStore.SaveAsync(plan, cancellationToken);\n\n        // Find all jobs for the plan and dispatch them.\n        var filter = new AlterationJobFilter\n        {\n            PlanId = plan.Id\n        };\n        var alterationJobStore = context.GetRequiredService<IAlterationJobStore>();\n        var alterationJobIds = await alterationJobStore.FindManyIdsAsync(filter, cancellationToken);\n\n        // Dispatch each job.\n        var alterationJobDispatcher = context.GetRequiredService<IAlterationJobDispatcher>();\n        foreach (var jobId in alterationJobIds)\n            await alterationJobDispatcher.DispatchAsync(jobId, cancellationToken);\n","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Alterations/Activities/DispatchAlterationJobs.cs#L32-L68","documentation":"The DispatchAlterationJobs activity finds the alteration plan via IAlterationPlanStore.FindAsync using a filter on the PlanId input and throws a FaultException with code AlterationFaultCodes.PlanNotFound when the lookup returns null. Like CompleteAlterationPlan, this is a workflow fault so callers can catch it and route the workflow into an error path.","triggerScenarios":"Executing DispatchAlterationJobs with a PlanId input for which FindAsync returns no plan (nonexistent ID, deleted plan, wrong tenant scope, or plan not yet persisted).","commonSituations":"Dispatching jobs for a plan created in a different tenant; race where the plan was deleted after being queued; misspelled or stale plan ID stored in workflow input from an earlier failed run.","solutions":["Verify the PlanId input refers to a persisted alteration plan visible to the current tenant.","Persist the plan before dispatching jobs for it.","Add a workflow fault handler for AlterationFaultCodes.PlanNotFound to handle missing plans.","Confirm the store connection/tenant scope used at runtime matches where the plan was saved."],"exampleFix":"// before\nawait workflowInvoker.DispatchAlterationJobsAsync(planId); // planId may not exist\n\n// after\nvar plan = await alterationPlanStore.FindAsync(new AlterationPlanFilter { Id = planId }, ct);\nif (plan == null)\n    throw new InvalidOperationException($\"Cannot dispatch jobs: plan {planId} not found.\");\nawait workflowInvoker.DispatchAlterationJobsAsync(planId);","handlingStrategy":"try-catch","validationCode":"var plan = await alterationPlanStore.FindAsync(new AlterationPlanFilter { Id = planId }, ct);\nif (plan is null)\n    throw new InvalidOperationException($\"Plan '{planId}' not found; ensure it is persisted and tenant-visible before dispatching jobs.\");","typeGuard":"bool PlanExists(AlterationPlan? plan) => plan is not null;","tryCatchPattern":"try\n{\n    await workflow.RunAsync(instance, ct);\n}\ncatch (FaultException ex) when (ex.Code == AlterationFaultCodes.PlanNotFound)\n{\n    logger.LogError(\"Cannot dispatch alteration jobs: {Message}\", ex.Message);\n}","preventionTips":["Persist the alteration plan before scheduling DispatchAlterationJobs.","Pass plan IDs from trusted store lookups, not raw external input.","Handle AlterationFaultCodes.PlanNotFound in workflow fault handlers to fail gracefully."],"tags":["workflow-fault","alterations","resource-not-found"],"backgroundTag":"record-not-found","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}