{"record":{"id":"154777e3b4d8bcd9","repo":"elsa-workflows/elsa-core","slug":"workflow-instance-not-found-backgroundactivityinvoker","errorCode":null,"errorMessage":"Workflow instance not found","messagePattern":"Workflow instance not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Runtime/Services/BackgroundActivityInvoker.cs","lineNumber":31,"sourceCode":"    IBookmarkQueue bookmarkQueue,\n    IWorkflowInstanceManager workflowInstanceManager,\n    IWorkflowDefinitionService workflowDefinitionService,\n    IVariablePersistenceManager variablePersistenceManager,\n    IActivityInvoker activityInvoker,\n    IActivityPropertyLogPersistenceEvaluator activityPropertyLogPersistenceEvaluator,\n    WorkflowHeartbeatGeneratorFactory workflowHeartbeatGeneratorFactory,\n    IServiceProvider serviceProvider,\n    ILogger<BackgroundActivityInvoker> logger)\n    : IBackgroundActivityInvoker\n{\n    private readonly ILogger _logger = logger;\n\n    /// <inheritdoc />\n    public async Task ExecuteAsync(ScheduledBackgroundActivity scheduledBackgroundActivity, CancellationToken cancellationToken = default)\n    {\n        var workflowInstanceId = scheduledBackgroundActivity.WorkflowInstanceId;\n        var workflowInstance = await workflowInstanceManager.FindByIdAsync(workflowInstanceId, cancellationToken);\n        if (workflowInstance == null) throw new(\"Workflow instance not found\");\n        var workflowState = workflowInstance.WorkflowState;\n        var workflow = await workflowDefinitionService.FindWorkflowGraphAsync(workflowInstance.DefinitionVersionId, cancellationToken);\n        if (workflow == null) throw new(\"Workflow definition not found\");\n        var workflowExecutionContext = await WorkflowExecutionContext.CreateAsync(serviceProvider, workflow, workflowState, cancellationToken: cancellationToken);\n        var activityNodeId = scheduledBackgroundActivity.ActivityNodeId;\n        var activityExecutionContext = workflowExecutionContext.ActivityExecutionContexts.First(x => x.NodeId == activityNodeId);\n\n        using (workflowHeartbeatGeneratorFactory.CreateHeartbeatGenerator(workflowExecutionContext))\n        {\n            await variablePersistenceManager.LoadVariablesAsync(workflowExecutionContext);\n            activityExecutionContext.SetIsBackgroundExecution();\n            await activityInvoker.InvokeAsync(activityExecutionContext);\n            await variablePersistenceManager.SaveVariablesAsync(workflowExecutionContext);\n        }\n        await ResumeWorkflowAsync(activityExecutionContext, scheduledBackgroundActivity);\n    }\n\n    private async Task ResumeWorkflowAsync(ActivityExecutionContext activityExecutionContext, ScheduledBackgroundActivity scheduledBackgroundActivity)","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Runtime/Services/BackgroundActivityInvoker.cs#L13-L49","documentation":"Thrown by BackgroundActivityInvoker.ExecuteAsync when the workflow instance referenced by the scheduled background activity (ScheduledBackgroundActivity.WorkflowInstanceId) cannot be loaded via IWorkflowInstanceManager.FindByIdAsync. The background invoker resumes a bookmarked activity of an existing instance; if the instance row is gone (deleted, pruned by retention, or never existed), it cannot proceed.","triggerScenarios":"A queued background activity (e.g. from a workflow executor queue such as DispatchWorkflow's background dispatch) executes after the workflow instance was deleted or never persisted; the ID in the message is stale or from another environment/database.","commonSituations":"Retention/cleanup jobs deleting finished or stale instances while background work is still queued; manually purging instances from the database; running queue messages across environments sharing a queue but not the instance store; crash-recovery replays referencing instances removed during cleanup.","solutions":["Check that the workflow instance ID in the scheduled activity exists (workflowInstanceManager.FindByIdAsync or the instances API); if it was deleted intentionally, discard the stale queue message.","Verify the background worker connects to the same database/tenant that owns the instance (connection string / tenant mismatch is common).","Review retention or cleanup jobs: order deletions after all queued background activities for the instance are drained.","Re-run or re-trigger the workflow if the instance was lost and the message is unrecoverable; make queue consumers idempotent for missing instances."],"exampleFix":"// before: blindly queue and resume\nawait workflowInboxManager.SubmitAsync(new NewWorkflowInboxMessage { ... });\n\n// after: skip resume when the instance no longer exists\nvar instance = await workflowInstanceManager.FindByIdAsync(instanceId, ct);\nif (instance == null)\n{\n    logger.LogWarning(\"Skipping background activity for missing instance {InstanceId}\", instanceId);\n    return;\n}","handlingStrategy":"try-catch","validationCode":"var instance = await workflowInstanceManager.FindByIdAsync(workflowInstanceId, ct);\nif (instance is null)\n{\n    logger.LogWarning(\"Background activity for workflow instance {InstanceId} skipped: instance not found.\", workflowInstanceId);\n    return;\n}","typeGuard":"if (workflowInstance is null) return; // narrow after FindByIdAsync before using instance","tryCatchPattern":"try\n{\n    await backgroundActivityInvoker.ExecuteAsync(scheduledBackgroundActivity, ct);\n}\ncatch (Exception ex) when (ex.Message == \"Workflow instance not found\")\n{\n    logger.LogWarning(ex, \"Dropping background activity {ActivityId}: instance {InstanceId} no longer exists.\",\n        scheduledBackgroundActivity.Id, scheduledBackgroundActivity.WorkflowInstanceId);\n}","preventionTips":["Ensure retention/cleanup jobs delete instances only after their queued background activities are drained.","Point background workers at the same database and tenant as the workflow runtime that queued the activity.","Make background activity consumers idempotent and tolerant of stale queue messages.","Monitor for this error as a signal of purge jobs racing live workflow execution."],"tags":["workflow","dotnet","background-activity","persistence","elsa"],"backgroundTag":"entity-not-found","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}