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
- Ensure every code path in your placement logic calls Zone("...") before returning/locating.
- In placement.json, provide a "place" value that includes a zone (e.g., "Content:after" or "Sidebar:10"), not just a tab or wrapper.
- 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
- Always call Zone() first when chaining PlacementLocationBuilder
- Validate placement.json entries include a zone in their 'place' value
- Default conditional placement paths to a fallback zone
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
- The 'Default' tenant can't be removed.
- ,
- Content part name must start with a letter
- Content part name contains invalid characters
- Content field name must start with a letter
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)