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
- Give the provider a public no-arg constructor with no runtime dependencies in its body
- Move CDI/config lookups out of the constructor into threadContext()
- Verify the class implements org.eclipse.microprofile.context.ThreadContextProvider
- 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
- Keep ThreadContextProvider constructors empty and side-effect free
- Never inject CDI beans or runtime config in the provider constructor
- Keep META-INF/services entries in sync with actual classes
- Test provider loading in a plain JVM before adding to the app
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
- Use GeneratedServiceProviderBuildItem to register service pr
- Failed to load the condition class ${testClassName} for capa
- Unable to load the datasource driver <driverName> for the <f
- Unable to load the config property type: ${className}
- Injected class not found in index:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5dc8f8618c67fb62.
Report an issue: GitHub.