OrchardCMS/OrchardCore · critical · InvalidOperationException

The content item is missing a 'ContentItemId'.

Error message

The content item is missing a 'ContentItemId'.

What it means

DefaultContentManager.CreateContentItemVersionAsync throws InvalidOperationException when the ContentItem has no ContentItemId. Versioned creation is only for items that already have an identity (loaded or built via NewAsync); a new item must be created through NewAsync so the manager can assign the ID.

Solutions

  1. Create the item via await _contentManager.NewAsync("TypeName", VersionOptions.Draft) so ContentItemId is assigned.
  2. If versioning an existing item, load it with _contentManager.GetAsync(contentItemId, VersionOptions.*) instead of constructing a new instance.
  3. Check your deserialization/import code preserves the ContentItemId property.
  4. Wrap the call in try/catch InvalidOperationException and fall back to NewAsync for genuinely new items.

Example fix

// before
var item = new ContentItem { ContentType = "Article" };
await _contentManager.CreateContentItemVersionAsync(item);

// after
var item = await _contentManager.NewAsync("Article", VersionOptions.Draft);
await _contentManager.CreateContentItemVersionAsync(item);
Defensive patterns

Strategy: try-catch

Validate before calling

if (string.IsNullOrEmpty(contentItem.ContentItemId))
{
    // must create via NewAsync before versioning
}

Type guard

bool CanCreateVersion(ContentItem item) => item is not null && !string.IsNullOrEmpty(item.ContentItemId);

Try / catch

try
{
    await _contentManager.CreateContentItemVersionAsync(item);
}
catch (InvalidOperationException)
{
    // fall back: create via NewAsync for genuinely new items
    var fresh = await _contentManager.NewAsync(item.ContentType, VersionOptions.Draft);
    // copy fields/parts then create
}

Prevention

When it happens

Trigger: Calling IContentManager.CreateContentItemVersionAsync with a ContentItem constructed with 'new ContentItem()' instead of IContentManager.NewAsync, or deserializing/hand-building an item and dropping its ContentItemId, or passing a default-constructed item to SaveContentItemAsync paths that route into version creation.

Common situations: Import/migration scripts that build ContentItem objects manually, unit tests constructing content items by hand, custom modules cloning items but clearing ContentItemId, serialization round-trips that omit the id property.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/OrchardCore/OrchardCore.ContentManagement/DefaultContentManager.cs:1002

        var context = new CloneContentContext(contentItem, cloneContentItem);

        context.CloneContentItem.Data = contentItem.Data.Clone();

        await Handlers.InvokeAsync((handler, context) => handler.CloningAsync(context), context, _logger);

        await _session.SaveAsync(context.CloneContentItem);

        await ReversedHandlers.InvokeAsync((handler, context) => handler.ClonedAsync(context), context, _logger);

        return context.CloneContentItem;
    }

    private async Task<ContentValidateResult> CreateContentItemVersionAsync(ContentItem contentItem, IEnumerable<ContentItem> evictionVersions = null)
    {
        if (string.IsNullOrEmpty(contentItem.ContentItemId))
        {
            // NewAsync should be used to create new content items.
            throw new InvalidOperationException($"The content item is missing a '{nameof(ContentItem.ContentItemId)}'.");
        }

        // Initializes the Id as it could be interpreted as an updated object when added back to YesSql
        contentItem.Id = 0;

        // Maintain modified and published dates as these will be reset by the Create Handlers
        var modifiedUtc = contentItem.ModifiedUtc;
        var publishedUtc = contentItem.PublishedUtc;
        var owner = contentItem.Owner;
        var author = contentItem.Author;

        if (string.IsNullOrEmpty(contentItem.ContentItemVersionId))
        {
            contentItem.ContentItemVersionId = _idGenerator.GenerateUniqueId(contentItem);
        }

        // Remove previous latest item or they will continue to be listed as latest.
        // When importing a new draft the existing latest must be set to false. The creating version wins.

View on GitHub (pinned to 4306c0717f)