OrchardCMS/OrchardCore · error · InvalidOperationException

The 'UpdateContentTask' can't update the content item as it…

Error message

The 'UpdateContentTask' can't update the content item as it is executed inline from a starting 'ContentDraftSavedEvent' of the same content type, which would result in an infinitive loop.

What it means

UpdateContentTask refuses to update (save draft) a content item when executed inline from a ContentDraftSavedEvent workflow of the same content type. Saving a draft within that draft-saved event would re-fire the event recursively, so the task throws InvalidOperationException up front.

Solutions

  1. Set Publish=true on the UpdateContentTask so it publishes rather than re-saving a draft.
  2. Remove the ContentDraftSavedEvent start activity or restrict its content type filter.
  3. Move the update logic into a handler (e.g. ContentHandler updating during Saving) instead of a workflow.
  4. Trigger the workflow from a different event type that the update operation does not raise.

Example fix

// before: UpdateContentTask with Publish = false inside a ContentDraftSavedEvent workflow
// after
// In the workflow editor set UpdateContentTask.Publish = true,
// or replace the UpdateContentTask with a content handler that mutates the item before save.
Defensive patterns

Strategy: validation

Validate before calling

bool wouldLoop = !task.Publish && inlineEvent.Name == nameof(ContentDraftSavedEvent);
if (wouldLoop) throw new InvalidOperationException("Set Publish=true or change the start event.");

Try / catch

try { await workflowManager.RunWorkflowAsync(...); } catch (InvalidOperationException ex) when (ex.Message.Contains("UpdateContentTask")) { logger.LogWarning(ex, "Inline draft-save loop blocked"); }

Prevention

When it happens

Trigger: A workflow starts with a ContentDraftSavedEvent activity for a content type and its UpdateContentTask has Publish=false; executing the task inline saves a draft, re-triggering the same event.

Common situations: Developer wires a 'modify on save' automation (e.g. normalizing fields on every draft save) and keeps the default Publish=false, causing the task to loop against the very event that started it.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/0b5d2cdefce24071. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Contents/Workflows/Activities/UpdateContentTask.cs:122

        {
            throw new InvalidOperationException($"The '{nameof(UpdateContentTask)}' failed to retrieve the content item.");
        }

        if (!inlineEventOfSameContentItemId && InlineEvent.IsStart && InlineEvent.ContentType == contentItem.ContentType)
        {
            if (InlineEvent.Name == nameof(ContentUpdatedEvent))
            {
                throw new InvalidOperationException($"The '{nameof(UpdateContentTask)}' can't update the content item as it is executed inline from a starting '{nameof(ContentUpdatedEvent)}' of the same content type, which would result in an infinitive loop.");
            }

            if (Publish && InlineEvent.Name == nameof(ContentPublishedEvent))
            {
                throw new InvalidOperationException($"The '{nameof(UpdateContentTask)}' can't publish the content item as it is executed inline from a starting '{nameof(ContentPublishedEvent)}' of the same content type, which would result in an infinitive loop.");
            }

            if (!Publish && InlineEvent.Name == nameof(ContentDraftSavedEvent))
            {
                throw new InvalidOperationException($"The '{nameof(UpdateContentTask)}' can't update the content item as it is executed inline from a starting '{nameof(ContentDraftSavedEvent)}' of the same content type, which would result in an infinitive loop.");
            }
        }

        if (!string.IsNullOrWhiteSpace(ContentProperties.Expression))
        {
            var contentProperties = await _expressionEvaluator.EvaluateAsync(ContentProperties, workflowContext, _javaScriptEncoder);
            contentItem.Merge(JsonNode.Parse(contentProperties), new JsonMergeSettings { MergeArrayHandling = MergeArrayHandling.Replace });
        }

        if (!inlineEventOfSameContentItemId)
        {
            await ContentManager.UpdateAsync(contentItem);
        }

        var result = await ContentManager.ValidateAsync(contentItem);

        if (result.Succeeded)
        {

View on GitHub (pinned to 4306c0717f)