QuestPDF/QuestPDF · error · DocumentComposeException
The Layers component needs to have exactly one primary layer
Error message
The Layers component needs to have exactly one primary layer. It has {primaryLayers}. What it means
The Layers component's Validate() also throws when more than one primary layer exists, because multiple primary layers would conflict over which content drives paging and target length. The message interpolates the actual count. Exactly one PrimaryLayer() call is permitted per Layers handler.
Source
Thrown at src/dotnet/library/QuestPDF/Fluent/LayerExtensions.cs:58
public IContainer Layer() => Layer(false);
/// <summary>
/// Sets the primary content for the container.
/// </summary>
/// <remarks>
/// Exactly one primary layer should be defined.
/// </remarks>
public IContainer PrimaryLayer() => Layer(true);
internal void Validate()
{
var primaryLayers = Layers.Children.Count(x => x.IsPrimary);
if (primaryLayers == 0)
throw new DocumentComposeException("The Layers component needs to have exactly one primary layer. It has none.");
if (primaryLayers != 1)
throw new DocumentComposeException($"The Layers component needs to have exactly one primary layer. It has {primaryLayers}.");
}
}
public static class LayerExtensions
{
/// <summary>
/// <para>Adds content either underneath (as a background) or on top of (as a watermark) the main content.</para>
/// <para>The main layer supports paging, can span multiple pages, and determines the container's target length.</para>
/// <para>Additional layers can also span multiple pages and are repeated on each one.</para>
/// <a href="https://www.questpdf.com/api-reference/layers.html">Learn more</a>
/// </summary>
/// <param name="handler">Handler for defining content of the container, including exactly one primary layer and any additional layers in a specified order.</param>
public static void Layers(this IContainer element, Action<LayersDescriptor> handler)
{
var descriptor = new LayersDescriptor();
handler(descriptor);
descriptor.Validate();View on GitHub (pinned to 43ab125596)
Solutions
- Keep exactly one desc.PrimaryLayer() in the handler; convert extras to desc.Layer() (secondary/background/watermark).
- Audit the handler for all PrimaryLayer() calls and retain a single one.
- Decide which content is the main flow and nest the rest as secondary layers.
Example fix
// before
container.Layers(desc => {
desc.PrimaryLayer().Text("a");
desc.PrimaryLayer().Text("b"); // count=2 -> throws
});
// after
container.Layers(desc => {
desc.PrimaryLayer().Text("a");
desc.Layer().Text("b"); // secondary layer
}); Defensive patterns
Strategy: validation
Validate before calling
container.Layers(desc => {
desc.PrimaryLayer().Element(mainBody); // single primary
foreach (var extra in extras)
desc.Layer().Element(extra); // secondary layers, not primary
}); Type guard
// Guard at authoring time: search the Layers handler for 'PrimaryLayer' and ensure count == 1. // Combine all main content into the single primary layer; use desc.Layer() for the rest.
Try / catch
try { /* generate document */ }
catch (DocumentComposeException ex) when (ex.Message.Contains("exactly one primary layer")) {
// Remove duplicate PrimaryLayer() calls; convert extras to desc.Layer().
throw;
} Prevention
- Keep exactly one desc.PrimaryLayer() per Layers handler.
- Convert duplicate primaries into secondary layers.
- Review copy-pasted Layers blocks for duplicated primary calls.
When it happens
Trigger: Calling desc.PrimaryLayer() two or more times within a single .Layers(handler) block.
Common situations: Copy-paste that duplicated PrimaryLayer(); merging two layout fragments that each declared their own primary; misunderstanding that Layer(true)/PrimaryLayer must be unique.
Related errors
- The Layers component needs to have exactly one primary layer
- You should not assign multiple child elements to a single-ch
- {prefix} A cell must span at least one row. Got {cell.RowSpa
- {prefix} Cell starts at column that does not exist. Cell det
- {prefix} Table cell location is incorrect. Cell spans over c
AI-assisted analysis of QuestPDF/QuestPDF@43ab125596 (2026-08-13).
Data as JSON: /api/errors/24b1b72739f67c2c.
Report an issue: GitHub.