OrchardCMS/OrchardCore · error · InvalidOperationException

Zone is required. Call Zone() before calling Build().

Error message

Zone is required. Call Zone() before calling Build().

What it means

PlacementLocationBuilder fluently builds a PlacementInfo (zone, position, alternates, etc.). Build() requires a zone to have been set via Zone(); otherwise the resulting PlacementInfo would be unusable for shape placement, so it throws InvalidOperationException("Zone is required. Call Zone() before calling Build().").

Solutions

  1. Ensure every code path in your placement logic calls Zone("...") before returning/locating.
  2. In placement.json, provide a "place" value that includes a zone (e.g., "Content:after" or "Sidebar:10"), not just a tab or wrapper.
  3. Check conditional builder chains: if placement depends on a setting, fall back to a default zone.

Example fix

// before
var location = new PlacementLocationBuilder()
    .Position("5")
    .Build();
// after
var location = new PlacementLocationBuilder()
    .Zone("Content")
    .Position("5")
    .Build();
Defensive patterns

Strategy: validation

Validate before calling

var builder = new PlacementLocationBuilder();
// ensure zone is set before Build():
var location = builder.Zone("Content").Build();

Try / catch

catch (InvalidOperationException ex) when (ex.Message.Contains("Zone is required")) { logger.LogError(ex, "Placement for {ShapeType} omitted a zone", shapeType); }

Prevention

When it happens

Trigger: Calling Build() (directly or via ToString()/Location) on a PlacementLocationBuilder without ever calling Zone(...) — e.g., setting only Position or Tab in placement code.

Common situations: Programmatic placement (IDisplayDriver placement methods) where a code path skips Zone() conditionally; malformed placement.json entries that omit the zone but set other keys converted into a builder; refactors that dropped the Zone() call.

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/3e6ad50af012cd5a. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore/OrchardCore.DisplayManagement/Descriptors/PlacementLocationBuilder.cs:170

        _cachedPlacementInfo = null;
        return this;
    }

    /// <summary>
    /// Builds a <see cref="PlacementInfo"/> instance from the current builder state.
    /// </summary>
    /// <returns>A new <see cref="PlacementInfo"/> with the configured location.</returns>
    /// <exception cref="InvalidOperationException">Thrown when <see cref="Zone"/> has not been called.</exception>
    public PlacementInfo Build()
    {
        if (_cachedPlacementInfo != null)
        {
            return _cachedPlacementInfo;
        }

        if (string.IsNullOrEmpty(_zone))
        {
            throw new InvalidOperationException("Zone is required. Call Zone() before calling Build().");
        }

        // Create GroupingMetadata directly without string allocation.
        var tabGrouping = !string.IsNullOrEmpty(_tabName)
            ? new GroupingMetadata(_tabName, _tabPosition)
            : GroupingMetadata.Empty;

        var cardGrouping = !string.IsNullOrEmpty(_cardName)
            ? new GroupingMetadata(_cardName, _cardPosition)
            : GroupingMetadata.Empty;

        var columnGrouping = !string.IsNullOrEmpty(_columnName)
            ? new GroupingMetadata(_columnName, _columnPosition, _columnWidth)
            : GroupingMetadata.Empty;

        // Split zones only once - use the zone string directly if no dots.
        var zones = _zone.Contains('.')
            ? _zone.Split('.')

View on GitHub (pinned to 4306c0717f)