theonedev/onedev · error · WicketRuntimeException

Cannot modify component hierarchy after render phase has sta

Error message

Cannot modify component hierarchy after render phase has started (page version cant change then anymore)

What it means

checkHierarchyChange() throws WicketRuntimeException when code tries to add/remove/replace components while the page is being rendered (FLAG_RENDERING is set) and the component is not auto-added. Once rendering started, the page version is committed and structural changes would corrupt the rendered output, so Wicket forbids them.

Source

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

				findMarkupStream().throwMarkupException(msg);
			}
		}
	}

	/**
	 * Checks whether the hierarchy may be changed at all, and throws an exception if this is not
	 * the case.
	 * 
	 * @param component
	 *            the component which is about to be added or removed
	 */
	protected void checkHierarchyChange(final Component component)
	{
		// Throw exception if modification is attempted during rendering
		if (getFlag(FLAG_RENDERING) && !component.isAuto())
		{
			throw new WicketRuntimeException(
				"Cannot modify component hierarchy after render phase has started (page version cant change then anymore)");
		}
	}

	/**
	 * Detaches the model for this component if it is detachable.
	 */
	protected void detachModel()
	{
		IModel<?> model = getModelImpl();
		if (model != null)
		{
			model.detach();
		}
		// also detach the wrapped model of a component assigned wrap (not
		// inherited)
		if (model instanceof IWrapModel && !getFlag(FLAG_INHERITABLE_MODEL))
		{

View on GitHub (pinned to d44925c47c)

Solutions

  1. Move hierarchy changes earlier in the lifecycle: constructor, onInitialize, or onBeforeRender before the render flag is set.
  2. If the change must happen during render, mark the component auto-added (component.setAuto(true)) or pre-build children in onInitialize.
  3. Use AJAX mechanisms (target.add / add children before rendering) instead of mutating the hierarchy mid-render.
  4. Check for accidental render-time mutation, e.g. calling add() inside renderHead or onRender.

Example fix

// before
@Override
protected void onBeforeRender() {
    add(new Label("extra")); // may run after render started
    super.onBeforeRender();
}
// after
@Override
protected void onInitialize() {
    super.onInitialize();
    add(new Label("extra")); // safe: before render phase
}
Defensive patterns

Strategy: validation

Validate before calling

if (component.getPage() != null && component.findParent(Page.class) != null && component.isPreparedForRender()) {
    throw new IllegalStateException("too late to modify hierarchy");
}

Try / catch

try { parent.add(child); } catch (WicketRuntimeException e) { target.add(parent); // or restructure to build children in onInitialize }

Prevention

When it happens

Trigger: Calling add(), remove(), replace() or similar hierarchy mutations from code that runs during rendering: onBeforeRender of a sibling, during renderHead, inside render of another component, or from behaviors rendering late.

Common situations: Dynamically adding components in onBeforeRender after render phase began; updating a ListView during rendering; adding components from an AJAX request handler that runs mid-render; page-relative lazy initialization done too late.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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