theonedev/onedev · error · ExplicitException

Page classes should extend from BasePage.

Error message

Page classes should extend from BasePage.

What it means

OneDev's WebApplication installs an Wicket onInstantiation listener that enforces every Page component instantiated in the application extends BasePage (with narrow exceptions for AbstractErrorPage and BrowserInfoPage). This guarantees consistent page chrome, security checks, and layout. If a custom Page class is registered that bypasses BasePage, the framework throws this ExplicitException immediately at instantiation time.

Source

Thrown at server-core/src/main/java/io/onedev/server/web/WebApplication.java:174

		 * a user visits the page, the page instance may not get written to disk timely due to
		 * page synchronous writing. So adding an in-memory cache is important to compensate the
		 * page written latency; otherwise, user may experience odd exceptions such as 
		 * ComponentNotFound when visit a page instance again after it is being created
		 */
		getStoreSettings().setInmemoryCacheSize(1000);
		
		getRequestCycleSettings().setTimeout(Duration.minutes(30));
		
		getComponentInstantiationListeners().add(new GuiceComponentInjector(this, AppLoader.injector));
		getComponentInstantiationListeners().add(new IComponentInstantiationListener() {
			
			@Override
			public void onInstantiation(Component component) {
				if ((component instanceof Page) 
						&& !(component instanceof AbstractErrorPage) 
						&& !(component instanceof BasePage)
						&& !(component instanceof BrowserInfoPage)) {
					throw new ExplicitException("Page classes should extend from BasePage.");
				} else if (component instanceof Link && !(component instanceof BookmarkablePageLink)) {
					component.add(AttributeAppender.append("rel", "nofollow"));
				}
			}
		});
		
		getSessionListeners().add(new ISessionListener() {

			@Override
			public void onCreated(Session session) {
			}

			@Override
			public void onUnbound(String sessionId) {
			}
						
		});
		getAjaxRequestTargetListeners().add(new AjaxRequestTarget.IListener() {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Make the page class extend io.onedev.server.web.page.base.BasePage (or a subclass like BasePageContent or a layout page) instead of WebPage.
  2. If the page is intentionally an error page, extend AbstractErrorPage instead.
  3. If the page only handles browser-info handshakes, use/extend BrowserInfoPage which is whitelisted.

Example fix

// before
public class MyCustomPage extends WebPage { ... }

// after
import io.onedev.server.web.page.base.BasePage;
public class MyCustomPage extends BasePage { ... }
Defensive patterns

Strategy: validation

Validate before calling

if (Page.class.isAssignableFrom(pageClass)
        && !AbstractErrorPage.class.isAssignableFrom(pageClass)
        && !BasePage.class.isAssignableFrom(pageClass)
        && !BrowserInfoPage.class.isAssignableFrom(pageClass)) {
    throw new IllegalStateException(pageClass + " must extend BasePage");
}

Type guard

static boolean isAllowedPage(Component c) {
    return !(c instanceof Page) || c instanceof AbstractErrorPage
        || c instanceof BasePage || c instanceof BrowserInfoPage;
}

Prevention

When it happens

Trigger: Registering or navigating to a Wicket Page class that directly extends org.apache.wicket.markup.html.WebPage (or another Page base) but not io.onedev.server.web.page.base.BasePage, and is not an AbstractErrorPage or BrowserInfoPage subclass.

Common situations: Developers adding a new custom page/plugin page and extending WebPage out of habit; copying a plain Wicket example page into a OneDev plugin; refactoring a page to no longer extend BasePage.

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