quarkusio/quarkus · error · IllegalStateException
Failed to instantiate {{VIRTUAL_THREAD_BINDER_CLASSNAME}}
Error message
Failed to instantiate {{VIRTUAL_THREAD_BINDER_CLASSNAME}} What it means
VirtualThreadCollector collects metrics for virtual-thread-per-request scheduling by instantiating Micrometer's virtual-thread binder reflectively via Class.forName(VIRTUAL_THREAD_BINDER_CLASSNAME). The binder class only exists when the JDK/Micrometer build supports it; any failure to load or construct it (ClassNotFoundException, NoSuchMethodException, InstantiationException, InvocationTargetException) is wrapped in an IllegalStateException.
Source
Thrown at extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/virtualthreads/VirtualThreadCollector.java:74
}
} else {
this.tags = List.of();
}
this.binder = instantiated;
}
/**
* Use reflection to avoid calling a class touching Java 21+ APIs.
*
* @param tags the tags.
* @return the binder, {@code null} if the instantiation failed.
*/
public MeterBinder instantiate(List<Tag> tags) {
try {
Class<?> clazz = Class.forName(VIRTUAL_THREAD_BINDER_CLASSNAME);
return (MeterBinder) clazz.getDeclaredConstructor(Iterable.class).newInstance(tags);
} catch (Exception e) {
throw new IllegalStateException("Failed to instantiate " + VIRTUAL_THREAD_BINDER_CLASSNAME, e);
}
}
private Tag createTagFromEntry(String entry) {
String[] parts = entry.trim().split("=");
if (parts.length == 2) {
return Tag.of(parts[0], parts[1]);
} else {
throw new IllegalStateException("Invalid tag: " + entry + " (expected key=value)");
}
}
public MeterBinder getBinder() {
return binder;
}
public List<Tag> getTags() {
return tags;View on GitHub (pinned to e1c734241f)
Solutions
- Upgrade Micrometer (and Quarkus) to a version where VirtualThreadBinder exists and your JDK is 21+; disable the binder otherwise (quarkus.micrometer.binder.virtual-threads.enabled=false)
- Check the configured class name for typos and confirm the fully-qualified class is on the classpath in the target Micrometer version
- If building native, register the binder class for reflection (quarkus.native.additional-build-args with --reflect-config or @RegisterForReflection)
- Inspect the wrapped cause (e.getCause()) in the IllegalStateException stack trace to distinguish ClassNotFoundException vs constructor failure
Example fix
// before (application.properties on JDK 17, Micrometer without the binder) quarkus.micrometer.binder.virtual-threads.enabled=true // -> IllegalStateException: Failed to instantiate ... // after: run on JDK 21+ with a Micrometer that has the binder, or disable # quarkus.micrometer.binder.virtual-threads.enabled=false
Defensive patterns
Strategy: try-catch
Validate before calling
String cls = "io.micrometer.core.instrument.binder.jvm.VirtualThreadBinder";
boolean binderAvailable;
try {
Class.forName(cls);
binderAvailable = Runtime.version().feature() >= 21;
} catch (ClassNotFoundException e) {
binderAvailable = false;
}
// only enable quarkus.micrometer.binder.virtual-threads.enabled if binderAvailable Type guard
static boolean virtualThreadBinderSupported() {
try {
Class.forName("io.micrometer.core.instrument.binder.jvm.VirtualThreadBinder");
return true;
} catch (ClassNotFoundException e) {
return false;
}
} Try / catch
try {
MeterBinder binder = collector.instantiate(tags);
} catch (IllegalStateException e) {
log.warnf("Virtual thread metrics unavailable: %s (cause=%s)", e.getMessage(), e.getCause());
// proceed without virtual thread metrics
} Prevention
- Only enable the virtual-threads binder on JDK 21+ with a Micrometer version that ships VirtualThreadBinder
- Register the binder class for reflection when building a native image
- Read the IllegalStateException cause chain to pinpoint ClassNotFoundException vs constructor errors
- Check quarkus.micrometer.binder.virtual-threads.enabled against the actual runtime JDK in CI
When it happens
Trigger: quarkus.micrometer.binder.virtual-threads.enabled=true (or a binder class name configured) while running on a JDK without support, or with a Micrometer version that lacks/renamed the binder class, or where the class exists but its (Iterable) constructor fails.
Common situations: Enabling virtual thread metrics on JDK 19/20 previews or a Micrometer version older than 1.10.x where the VirtualThreadBinder did not exist; a custom VIRTUAL_THREAD_BINDER_CLASSNAME typo; running native-image where the reflectively-loaded class was not registered for reflection.
Related errors
- Couldn't extract all parameters information for constructor
- Failed to set dev services config
- Failed to set dev services override config
- Unable to find or load top command: <className>
- Unable to find the following conversion class: ${customConve
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/0153074e30add448.
Report an issue: GitHub.