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
- Make the page class extend io.onedev.server.web.page.base.BasePage (or a subclass like BasePageContent or a layout page) instead of WebPage.
- If the page is intentionally an error page, extend AbstractErrorPage instead.
- 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
- Always extend BasePage (or an existing OneDev page subclass) when creating new pages.
- Add a unit test that instantiates every registered page class to catch violations at build time.
- Search the plugin for 'extends WebPage' during code review.
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
- Base resource mapper should be used
- Invalid date range, expecting "yyyy-MM-dd to yyyy-MM-dd"
- Path '${mountPath}' should be mounted to a svg sprite resour
- Unable to find svg sprite resource mounted at: ${mountPath}
- Invalid number: ${token}
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/e2a7bbcfa56e84c8.
Report an issue: GitHub.