{"record":{"id":"c21bc50bd900be06","repo":"OrchardCMS/OrchardCore","slug":"the-deletecontenttask-can-t-delete-the-content-item-as-it-is","errorCode":null,"errorMessage":"The 'DeleteContentTask' can't delete the content item as it is executed inline from a starting 'ContentDeletedEvent' of the same content type, which would result in an infinitive loop.","messagePattern":"The 'DeleteContentTask' can't delete the content item as it is executed inline from a starting 'ContentDeletedEvent' of the same content type, which would result in an infinitive loop\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore.Modules/OrchardCore.Contents/Workflows/Activities/DeleteContentTask.cs","lineNumber":52,"sourceCode":"        {\n            return Outcome(\"Noop\");\n        }\n\n        var contentItem = await ContentManager.GetAsync(content.ContentItem.ContentItemId, VersionOptions.Latest);\n\n        if (contentItem == null)\n        {\n            if (content is ContentItemIdExpressionResult)\n            {\n                throw new InvalidOperationException($\"The '{nameof(DeleteContentTask)}' failed to retrieve the content item.\");\n            }\n\n            contentItem = content.ContentItem;\n        }\n\n        if (InlineEvent.IsStart && InlineEvent.ContentType == contentItem.ContentType && InlineEvent.Name == nameof(ContentDeletedEvent))\n        {\n            throw new InvalidOperationException($\"The '{nameof(DeleteContentTask)}' can't delete the content item as it is executed inline from a starting '{nameof(ContentDeletedEvent)}' of the same content type, which would result in an infinitive loop.\");\n        }\n\n        await ContentManager.RemoveAsync(contentItem);\n\n        return Outcome(\"Deleted\");\n    }\n}\n","sourceCodeStart":34,"sourceCodeEnd":60,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore.Modules/OrchardCore.Contents/Workflows/Activities/DeleteContentTask.cs#L34-L60","documentation":"DeleteContentTask throws this InvalidOperationException when it runs inline from a starting ContentDeletedEvent for a content item of the same type. Deleting the item inline would emit another ContentDeletedEvent, restarting the workflow and looping forever. Orchard Core guards against this recursion explicitly.","triggerScenarios":"Workflow starting with ContentDeletedEvent (IsStart=true, ContentType = X) containing a DeleteContentTask whose resolved contentItem.ContentType equals X and whose target is triggered inline during deletion of an X item.","commonSituations":"Cleanup workflows like 'when a Session is deleted, delete related materials' where the related content type is accidentally set to the same type; recursive cascade-delete chains between two types that reference each other.","solutions":["Ensure the DeleteContentTask targets a different content type than the ContentDeletedEvent trigger.","Note the task already Noops when the InlineEvent.ContentItemId equals the target's ContentItemId — check your expression does not resolve to the same item of the same type.","Restructure cascade deletes using content handlers/relations instead of an inline self-referencing workflow.","Catch InvalidOperationException in host workflow execution code and log the suppressed recursion."],"exampleFix":"// before\n// Trigger: ContentDeletedEvent { ContentType: \"Topic\" }, DeleteContentTask resolves a 'Topic' item\n// after\nDeleteContentTask { ContentItemId: '{{ related.ReplyContentItemId }}' } // delete a different type","handlingStrategy":"validation","validationCode":"// Before triggering a ContentDeletedEvent-started workflow\nif (triggerIsStart && triggerEvent == \"ContentDeletedEvent\" &&\n    string.Equals(resolvedTargetContentType, triggerContentType, StringComparison.OrdinalIgnoreCase) &&\n    string.Equals(resolvedTargetId, inlineEventContentItemId, StringComparison.OrdinalIgnoreCase))\n    throw new InvalidOperationException(\"DeleteContentTask would recurse on the same item/type; reconfigure.\");","typeGuard":null,"tryCatchPattern":"try { await workflowManager.TriggerEventAsync(nameof(ContentDeletedEvent), contentItem); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"DeleteContentTask\") && ex.Message.Contains(\"infinitive loop\"))\n{\n    logger.LogWarning(ex, \"Delete loop prevented; reconfigure cascade workflow.\");\n}","preventionTips":["Cascade-delete related content via content handlers, not self-referencing inline workflows.","Keep the delete target's content type different from the ContentDeletedEvent trigger type.","Remember the built-in Noop only protects the exact same ContentItemId, not same-type siblings.","Test deletion workflows with multi-item cascades."],"tags":["orchardcore","workflows","infinite-loop","contents"],"backgroundTag":"invalid-state-transition","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}