quarkusio/quarkus · error · RuntimeException

More than one Application class: ${jakartaRestApplicationCla

Error message

More than one Application class: ${jakartaRestApplicationClasses}

What it means

During deployment, ResteasyServerCommonProcessor scans the application index for concrete subclasses of jakarta.ws.rs.core.Application to determine the application path and which classes that Application selects. JAX-RS allows at most one Application subclass, so when more than one non-abstract Application class is found the build fails with this RuntimeException.

Source

Thrown at extensions/resteasy-classic/resteasy-server-common/deployment/src/main/java/io/quarkus/resteasy/server/common/deployment/ResteasyServerCommonProcessor.java:233

        final Set<String> excludedClasses;
        if (resteasyConfig.buildTimeConditionAware()) {
            excludedClasses = getExcludedClasses(buildTimeConditions);
        } else {
            excludedClasses = Collections.emptySet();
        }
        final Set<String> allowedClasses;
        final String appClass;
        if (resteasyConfig.ignoreApplicationClasses()) {
            applicationPath = null;
            allowedClasses = Collections.emptySet();
            appClass = null;
        } else {
            Collection<ClassInfo> jakartaRestApplicationClasses = index.getAllKnownSubclasses(ResteasyDotNames.APPLICATION)
                    .stream()
                    .filter(ci -> !ci.isAbstract()).collect(
                            Collectors.toSet());
            if (jakartaRestApplicationClasses.size() > 1) {
                throw new RuntimeException("More than one Application class: " + jakartaRestApplicationClasses);
            }
            if (jakartaRestApplicationClasses.isEmpty()) {
                applicationPath = null;
                allowedClasses = Collections.emptySet();
                appClass = null;
            } else {
                ClassInfo jakartaRestApplicationClass = jakartaRestApplicationClasses.iterator().next();
                applicationPath = jakartaRestApplicationClass.annotation(ResteasyDotNames.APPLICATION_PATH);
                allowedClasses = getAllowedClasses(jakartaRestApplicationClass);
                appClass = jakartaRestApplicationClass.name().toString();
            }

            jaxrsProvidersToRegisterBuildItem = getFilteredJaxrsProvidersToRegisterBuildItem(
                    jaxrsProvidersToRegisterBuildItem, allowedClasses, excludedClasses);
        }

        boolean filterClasses = !allowedClasses.isEmpty() || !excludedClasses.isEmpty();

View on GitHub (pinned to e1c734241f)

Solutions

  1. Delete or make abstract all but one jakarta.ws.rs.core.Application subclass in your project.
  2. Exclude the dependency JAR containing the extra Application class, or override/shade it out.
  3. If you need multiple paths, use a single Application with @ApplicationPath and split resources by path annotations, or migrate to Quarkus REST (RESTEasy Reactive) which doesn't require Application classes.

Example fix

// before
@ApplicationPath("/api")
public class App1 extends Application {}
@ApplicationPath("/v2")
public class App2 extends Application {} // build fails

// after
@ApplicationPath("/api")
public class App extends Application {}
Defensive patterns

Strategy: validation

Validate before calling

long count = Stream.concat(Arrays.stream(MyApplicationClasses.class.getDeclaredClasses()),
        // plus scan your dependencies
        Arrays.stream(knownAppClasses))
    .filter(c -> !Modifier.isAbstract(c.getModifiers()))
    .filter(jakarta.ws.rs.core.Application.class::isAssignableFrom)
    .count();
if (count > 1) throw new IllegalStateException("Only one concrete Application class is allowed: found " + count);

Type guard

static boolean isConcreteApplication(Class<?> c) {
    return jakarta.ws.rs.core.Application.class.isAssignableFrom(c) && !Modifier.isAbstract(c.getModifiers());
}

Try / catch

// This fails during Quarkus deployment (augmentation), so it cannot be caught at runtime.
// Guard instead in a build-time check or CI test:
// fail the build if more than one concrete Application subclass is on the classpath.

Prevention

When it happens

Trigger: Declaring two or more non-abstract classes extending jakarta.ws.rs.core.Application (with or without @ApplicationPath) in the same Quarkus application or its dependency JARs, triggering deployment build of the RESTEasy Classic server extension.

Common situations: Copy-pasting an Application class from another app; adding a library that itself ships an Application subclass; refactoring renamed Application classes leaving the old one behind.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/79008a4c46ffa87c. Report an issue: GitHub.