theonedev/onedev · error · ExplicitException

Base resource mapper should be used

Error message

Base resource mapper should be used

What it means

WebApplication.mount() overrides Wicket's mount to require that any IRequestMapper of type ResourceMapper also extends OneDev's BaseResourceMapper. BaseResourceMapper adds OneDev-specific handling (canonical URL generation etc.), so a raw Wicket ResourceMapper would break resource URL handling. A plain ResourceMapper passed to mount() triggers this ExplicitException.

Source

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

		setRequestCycleProvider(context -> new RequestCycle(context) {

			@Override
			protected UrlRenderer newUrlRenderer() {
				return new AbsoluteUrlRenderer(getRequest());
			}
			
		});
		
		mount(new BaseUrlMapper(this));
		
		for (WebApplicationConfigurator configurator: applicationConfigurators)
			configurator.configure(this);
	}

	@Override
	public void mount(IRequestMapper mapper) {
		if (mapper instanceof ResourceMapper && !(mapper instanceof BaseResourceMapper))
			throw new ExplicitException("Base resource mapper should be used");
		super.mount(mapper);
	}

	@Override
	public final IProvider<IExceptionMapper> getExceptionMapperProvider() {
		return new IProvider<>() {

			@Override
			public IExceptionMapper get() {
				return new DefaultExceptionMapper() {
					
					@Override
					protected IRequestHandler mapExpectedExceptions(Exception e, Application application) {
						RequestCycle requestCycle = RequestCycle.get();
						boolean isAjax = ((WebRequest) requestCycle.getRequest()).isAjax();
						if (isAjax && (e instanceof ListenerInvocationNotAllowedException || e instanceof ComponentNotFoundException || e instanceof InvalidBehaviorIdException))
							return EmptyAjaxRequestHandler.getInstance();

View on GitHub (pinned to d44925c47c)

Solutions

  1. Use OneDev's BaseResourceMapper (or a subclass) instead of a raw ResourceMapper when mounting.
  2. If you need custom mapper behavior, extend BaseResourceMapper and override only what you need.
  3. Check which init contributor mounts the mapper and replace it with the OneDev base class.

Example fix

// before
app.mount(new ResourceMapper("/assets", new MyResourceReference()));

// after
app.mount(new BaseResourceMapper("/assets", new MyResourceReference()));
Defensive patterns

Strategy: validation

Validate before calling

if (mapper instanceof ResourceMapper && !(mapper instanceof BaseResourceMapper)) {
    throw new IllegalStateException("Use BaseResourceMapper instead of raw ResourceMapper");
}
application.mount(mapper);

Type guard

static boolean isMountable(IRequestMapper m) {
    return !(m instanceof ResourceMapper) || m instanceof BaseResourceMapper;
}

Prevention

When it happens

Trigger: Calling application.mount(new ResourceMapper(...)) (or any ResourceMapper subclass that is not a BaseResourceMapper) during application/plugin initialization.

Common situations: Plugin authors following generic Wicket tutorials for mounting resource mappers; copying mapper code from a non-OneDev Wicket project into an OneDev initContributor.

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