theonedev/onedev · error · IllegalStateException

Placeholder tag set on a component that renders its body onl

Error message

Placeholder tag set on a component that renders its body only. Component id: %s.

What it means

A component that renders only its body (no own tag) had setOutputMarkupPlaceholderTag / FLAG_PLACEHOLDER set, which cannot work without a tag to render the placeholder into. As with the markup-id case, behavior is governed by NotRenderableErrorStrategy: throw IllegalStateException or log a warning.

Source

Thrown at server-core/src/main/java/org/apache/wicket/Component.java:2608

				}

				if (getFlag(FLAG_OUTPUT_MARKUP_ID))
				{
					String message = String.format("Markup id set on a component that renders its body only. " +
					                               "Markup id: %s, component id: %s.", getMarkupId(), getId());
					if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION)
					{
						throw new IllegalStateException(message);
					}
					log.warn(message);
				}
				if (getFlag(FLAG_PLACEHOLDER))
				{
					String message = String.format("Placeholder tag set on a component that renders its body only. " +
					                               "Component id: %s.", getId());
					if (notRenderableErrorStrategy == ExceptionSettings.NotRenderableErrorStrategy.THROW_EXCEPTION)
					{
						throw new IllegalStateException(message);
					}
					log.warn(message);
				}
			}
			else
			{
				renderComponentTag(tag);
			}
			markupStream.next();

			// Render the body only if open-body-close. Do not render if open-close.
			if (tag.isOpen())
			{
				// Render the body. The default strategy will simply call the component's
				// onComponentTagBody() implementation.
				getMarkupSourcingStrategy().onComponentTagBody(this, markupStream, tag);

				// Render close tag

View on GitHub (pinned to d44925c47c)

Solutions

  1. Remove setOutputMarkupPlaceholderTag(true) for body-only components.
  2. Set renderBodyOnly(false) so the placeholder tag can be rendered.
  3. Relax NotRenderableErrorStrategy if the placeholder is irrelevant.
  4. Only apply placeholders to components intended for Ajax replacement.
  5. Audit base classes/helpers that bulk-enable output flags.

Example fix

// before
field.setRenderBodyOnly(true);
field.setOutputMarkupPlaceholderTag(true);
// after
field.setRenderBodyOnly(false);
field.setOutputMarkupPlaceholderTag(true);
Defensive patterns

Strategy: validation

Validate before calling

if (component.isRenderBodyOnly() && component.getOutputMarkupPlaceholderTag()) { component.setOutputMarkupPlaceholderTag(false); }

Type guard

boolean canHavePlaceholder(Component c) { return !c.isRenderBodyOnly(); }

Try / catch

try { renderComponent(c); } catch (IllegalStateException e) { if (e.getMessage().contains("Placeholder tag")) { log.warn(e.getMessage()); } else { throw e; } }

Prevention

When it happens

Trigger: Calling setOutputMarkupPlaceholderTag(true) on a component with renderBodyOnly=true, then rendering it; strict error strategy configured in Application's ExceptionSettings.

Common situations: Global Ajax-refresh setup code applying setOutputMarkupPlaceholderTag(true) to all children; inline fields/text fields configured body-only; strict strategy enabled for catching Ajax mistakes early.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/ea49d1c159b55e11. Report an issue: GitHub.