quarkusio/quarkus · error · RuntimeException

Resource locator method returned object that was not a resou

Error message

Resource locator method returned object that was not a resource: 

What it means

ResourceLocatorHandler follows a resource locator method's return value to sub-resource classes. After unwrapping and injecting the returned object, it looks up routing targets by the object's class; if the class has no registered runtime resources, the returned object is not a recognized sub-resource and a RuntimeException is thrown naming the locator object.

Source

Thrown at independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java:80

            locatorClass = locator.getClass();
        }

        // in case of a subresource gets returned, we might not control the lifecycle of the subresource ourself
        // E.g. the user could return a singleton instance, or construct an instance on each invocation of the locator.
        // therefore, only inject into CDI Beans, where we already know they are constructed once for each request
        // (thanks to the requestScopedResources validation)
        // otherwise TCK JAXRSClient0015 fails
        Object unwrapped = null;
        if (clientProxyUnwrapper != null) {
            unwrapped = clientProxyUnwrapper.apply(locator);
        }
        if (unwrapped instanceof ResteasyReactiveInjectionTarget t && unwrapped != locator) {
            t.__quarkus_rest_inject(requestContext);
        }

        Map<String, RequestMapper<RuntimeResource>> target = findTarget(locatorClass);
        if (target == null) {
            throw new RuntimeException("Resource locator method returned object that was not a resource: " + locator);
        }

        RequestMapper<RuntimeResource> mapper = target.get(requestContext.getMethod());
        RequestMapper.RequestMatch<RuntimeResource> res;
        boolean hadNullMethodMapper;
        if (mapper != null) {
            res = findRequestMatch(mapper, requestContext);
            hadNullMethodMapper = false;
        } else {
            res = findRequestMatch(target.get(null), requestContext); //another layer of resource locators maybe
            // we set this without checking if we matched, but we only use it after
            // we check for a null mapper, so by the time we use it, it must have meant that
            // we had a matcher for a null method
            hadNullMethodMapper = true;

            if (res == null) {
                String requestMethod = requestContext.getMethod();
                if (requestMethod.equals(HttpMethod.HEAD)) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the returned class with @Path and give it HTTP method methods so it registers as a sub-resource class
  2. Return an instance of the correct sub-resource class from the locator
  3. Ensure the sub-resource class is in an indexed package of the application
  4. Verify the locator method has no @GET/@POST annotation (it must be a locator, not an endpoint)

Example fix

// before
class Sub { public String get() { return "x"; } } // no @Path
@Path("/root")
class Root {
  @Path("/sub")
  public Sub sub() { return new Sub(); }
}
// after
@Path("/sub")
class Sub {
  @GET public String get() { return "x"; }
}
Defensive patterns

Strategy: validation

Validate before calling

Object sub = locator();
if (sub == null || sub.getClass().getAnnotation(jakarta.ws.rs.Path.class) == null) {
    throw new IllegalStateException("Locator must return a @Path-annotated resource class");
}

Type guard

static boolean isSubResource(Object o) {
    return o != null && o.getClass().isAnnotationPresent(jakarta.ws.rs.Path.class);
}

Try / catch

try { return locator.locate(); } catch (RuntimeException e) { if (e.getMessage().startsWith("Resource locator method returned object")) { /* return correct @Path class instance */ } throw e; }

Prevention

When it happens

Trigger: A @Path method with no HTTP method annotation (locator) returns an object whose class was not itself scanned as a resource class (no @Path on the class, or not returned by a locator-registered class); returning a proxy, null-wrapped, or non-resource instance.

Common situations: Returning an instance of a class missing @Path; returning a class produced at runtime or from another module not indexed as a JAX-RS resource; typos where the locator returns a DTO instead of the sub-resource.

Related errors


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