{"record":{"id":"0c60dc5a43603d41","repo":"elsa-workflows/elsa-core","slug":"cannot-retract-an-unpublished-workflow-definition","errorCode":null,"errorMessage":"Cannot retract an unpublished workflow definition.","messagePattern":"Cannot retract an unpublished workflow definition\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionPublisher.cs","lineNumber":144,"sourceCode":"    }\n\n    /// <inheritdoc />\n    public async Task<WorkflowDefinition?> RetractAsync(string definitionId, CancellationToken cancellationToken = default)\n    {\n        var filter = WorkflowDefinitionHandle.ByDefinitionId(definitionId, VersionOptions.Published).ToFilter();\n        var definition = await workflowDefinitionStore.FindAsync(filter, cancellationToken);\n\n        if (definition == null)\n            return null;\n\n        return await RetractAsync(definition, cancellationToken);\n    }\n\n    /// <inheritdoc />\n    public async Task<WorkflowDefinition> RetractAsync(WorkflowDefinition definition, CancellationToken cancellationToken = default)\n    {\n        if (!definition.IsPublished)\n            throw new InvalidOperationException(\"Cannot retract an unpublished workflow definition.\");\n\n        definition.IsPublished = false;\n\n        await mediator.SendAsync(new WorkflowDefinitionRetracting(definition), cancellationToken);\n        await workflowDefinitionStore.SaveAsync(definition, cancellationToken);\n        await mediator.SendAsync(new WorkflowDefinitionRetracted(definition), cancellationToken);\n        return definition;\n    }\n\n    public async Task<WorkflowDefinition> RevertVersionAsync(string definitionId, int version, CancellationToken cancellationToken = default)\n    {\n        var latestVersionFilter = new WorkflowDefinitionFilter\n        {\n            DefinitionId = definitionId,\n            VersionOptions = VersionOptions.Latest\n        };\n        var latestVersion = await workflowDefinitionStore.FindAsync(latestVersionFilter, cancellationToken);\n        var lastVersionFilter = new WorkflowDefinitionFilter","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Workflows.Management/Services/WorkflowDefinitionPublisher.cs#L126-L162","documentation":"WorkflowDefinitionPublisher.RetractAsync only supports retracting definitions that are currently published. Attempting to retract an unpublished (draft or never-published) definition throws InvalidOperationException because retraction is meaningless without a published version.","triggerScenarios":"Calling IWorkflowDefinitionPublisher.RetractAsync with a WorkflowDefinition whose IsPublished is false — e.g. a fresh draft, an already-retracted definition, or an instance loaded from a store where the published flag was cleared.","commonSituations":"Double-retraction after a retry; retracting by ID where the definition was already retracted by another user/process; a race where the definition was unpublished between check and call.","solutions":["Check definition.IsPublished before calling RetractAsync and skip the call when false.","Re-fetch the definition from the store immediately before retracting to get the current publish state.","If the intent is to delete the draft instead, use the definition deletion API rather than retract."],"exampleFix":"// before\nawait publisher.RetractAsync(definition);\n// after\nif (definition.IsPublished)\n    await publisher.RetractAsync(definition);","handlingStrategy":"validation","validationCode":"if (!definition.IsPublished) throw new InvalidOperationException($\"Definition {definition.DefinitionId} is not published; nothing to retract.\");","typeGuard":null,"tryCatchPattern":"try { await publisher.RetractAsync(definition); } catch (InvalidOperationException) { /* already unpublished; treat as no-op */ }","preventionTips":["Always check IsPublished before retracting","Re-read the definition from the store before state transitions","Guard against duplicate retract requests with idempotency handling","Handle retraction results from concurrent users gracefully"],"tags":["workflow-definitions","invalid-state","publishing"],"backgroundTag":"invalid-state-transition","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}