quarkusio/quarkus · error · RuntimeException

Failed to instantiate declared ThreadContextProvider class:

Error message

Failed to instantiate declared ThreadContextProvider class: 

What it means

During static-init build of the context propagation extension, SmallRyeContextPropagationProcessor discovers all ThreadContextProvider implementations declared in META-INF/services and instantiates each via a no-arg constructor. If instantiation fails, the build step aborts with a RuntimeException naming the provider class, because a broken context provider would silently break context propagation.

Source

Thrown at extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java:76

        additionalBeans
                .produce(AdditionalBeanBuildItem.unremovableOf(SmallRyeContextPropagationProvider.class));
    }

    @BuildStep
    @Record(ExecutionTime.STATIC_INIT)
    void buildStatic(SmallRyeContextPropagationRecorder recorder, List<ThreadContextProviderBuildItem> threadContextProviders)
            throws ClassNotFoundException, IOException {
        List<ThreadContextProvider> discoveredProviders = new ArrayList<>();
        List<ContextManagerExtension> discoveredExtensions = new ArrayList<>();
        List<Class<?>> providers = threadContextProviders.stream().map(ThreadContextProviderBuildItem::getProvider)
                .collect(Collectors.toCollection(ArrayList::new));
        ServiceUtil.classesNamedIn(Thread.currentThread().getContextClassLoader(),
                "META-INF/services/" + ThreadContextProvider.class.getName()).forEach(providers::add);
        for (Class<?> provider : providers) {
            try {
                discoveredProviders.add((ThreadContextProvider) provider.getDeclaredConstructor().newInstance());
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                throw new RuntimeException("Failed to instantiate declared ThreadContextProvider class: " + provider.getName(),
                        e);
            }
        }
        for (Class<?> extension : ServiceUtil.classesNamedIn(Thread.currentThread().getContextClassLoader(),
                "META-INF/services/" + ContextManagerExtension.class.getName())) {
            try {
                discoveredExtensions.add((ContextManagerExtension) extension.getDeclaredConstructor().newInstance());
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                throw new RuntimeException("Failed to instantiate declared ThreadContextProvider class: " + extension.getName(),
                        e);
            }
        }

        recorder.configureStaticInit(discoveredProviders, discoveredExtensions);
    }

    @BuildStep
    @Record(ExecutionTime.RUNTIME_INIT)

View on GitHub (pinned to e1c734241f)

Solutions

  1. Give the provider a public no-arg constructor with no runtime dependencies in its body
  2. Move CDI/config lookups out of the constructor into threadContext()
  3. Verify the class implements org.eclipse.microprofile.context.ThreadContextProvider
  4. Check the service file entry names the correct fully-qualified class

Example fix

// before
class MyProvider implements ThreadContextProvider {
    MyProvider() { ConfigProvider.getConfig(); ... }
}
// after
class MyProvider implements ThreadContextProvider {
    public MyProvider() {}
    public ThreadContextSnapshot currentContext(Map<String, String> p) { ... }
}
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    var ctor = providerClass.getDeclaredConstructor();
    ctor.setAccessible(true);
    ctor.newInstance();
} catch (ReflectiveOperationException e) {
    throw new IllegalStateException("Bad ThreadContextProvider: " + providerClass.getName(), e);
}

Type guard

boolean validProvider(Class<?> c) {
    return ThreadContextProvider.class.isAssignableFrom(c)
        && !c.isInterface() && !Modifier.isAbstract(c.getModifiers())
        && Arrays.stream(c.getConstructors()).anyMatch(k -> k.getParameterCount() == 0);
}

Try / catch

try { runBuild(); }
catch (RuntimeException e) {
    if (e.getMessage().startsWith("Failed to instantiate declared ThreadContextProvider")) {
        log.error("Check constructor of provider: " + extractName(e.getMessage()));
    }
}

Prevention

When it happens

Trigger: A ThreadContextProvider service-declared class has no public no-arg constructor, is abstract, is not actually a ThreadContextProvider, or throws in its constructor when loaded at static init (e.g. it depends on runtime-only CDI beans or config).

Common situations: Adding a custom ThreadContextProvider that injects CDI beans or reads runtime config in its constructor; provider class from a dependency incompatible at build time; missing default constructor after refactor.

Related errors


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