quarkusio/quarkus · error · IllegalArgumentException

Failed to instantiate provider " + componentClass + ". Does

Error message

Failed to instantiate provider " + componentClass + ". Does it have a public no-arg constructor?

What it means

When registering a provider class, registerMpSpecificProvider instantiates MP-specific providers (ResponseExceptionMapper and ParamConverterProvider implementations) via their public no-arg constructor. If instantiation fails (abstract class, missing constructor, inaccessible constructor, throwing constructor), it wraps the reflective exception in this IllegalArgumentException. Non-MP providers (filters, interceptors) are instantiated elsewhere and do not hit this path.

Source

Thrown at extensions/resteasy-reactive/rest-client/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java:470

    public RestClientBuilderImpl register(Object component, Map<Class<?>, Integer> contracts) {
        registerMpSpecificProvider(component);
        clientBuilder.register(component, contracts);
        return this;
    }

    @Override
    public RestClientBuilderImpl baseUri(URI uri) {
        this.uri = uri;
        return this;
    }

    private void registerMpSpecificProvider(Class<?> componentClass) {
        if (ResponseExceptionMapper.class.isAssignableFrom(componentClass)
                || ParamConverterProvider.class.isAssignableFrom(componentClass)) {
            try {
                registerMpSpecificProvider(componentClass.getDeclaredConstructor().newInstance());
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                throw new IllegalArgumentException("Failed to instantiate provider " + componentClass
                        + ". Does it have a public no-arg constructor?", e);
            }
        }
    }

    private void registerMpSpecificProvider(Object component) {
        if (component instanceof ResponseExceptionMapper) {
            exceptionMappers.add((ResponseExceptionMapper<?>) component);
        }
        if (component instanceof ParamConverterProvider) {
            paramConverterProviders.add((ParamConverterProvider) component);
        }
    }

    @Override
    public RestClientBuilderImpl queryParamStyle(final QueryParamStyle style) {
        queryParamStyle = style;
        return this;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add a public no-argument constructor to the provider class (or make the existing constructor public).
  2. Register an instance instead of a class: builder.register(new MyMapper(...)) or use @RegisterProvider / CDI-managed registration for annotation-registered providers.
  3. Ensure the class is concrete (not abstract or an interface).

Example fix

// before
public class MyMapper implements ResponseExceptionMapper {
    public MyMapper(String config) { ... } // no no-arg ctor
}

// after
public class MyMapper implements ResponseExceptionMapper {
    public MyMapper() { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<?> c = MyMapper.class;
boolean ok = !java.lang.reflect.Modifier.isAbstract(c.getModifiers());
try { c.getDeclaredConstructor().newInstance(); } catch (Exception e) { /* fail fast before register */ }

Type guard

boolean instantiableProvider(Class<?> c) {
    return !c.isInterface() && !java.lang.reflect.Modifier.isAbstract(c.getModifiers())
        && java.util.Arrays.stream(c.getDeclaredConstructors())
            .anyMatch(k -> k.getParameterCount() == 0 && java.lang.reflect.Modifier.isPublic(k.getModifiers()));
}

Try / catch

try {
    builder.register(MyMapper.class);
} catch (IllegalArgumentException e) {
    builder.register(new MyMapper(dep)); // instance fallback
}

Prevention

When it happens

Trigger: builder.register(MyResponseExceptionMapper.class) or register(MyParamConverterProvider.class) where that class lacks a public no-arg constructor, is abstract, or its constructor throws.

Common situations: Registering a mapper class that requires constructor injection (e.g. takes a config parameter); registering an abstract base mapper class by mistake; CDI users forgetting that class-based registration here means reflective instantiation, not CDI creation.

Related errors


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