{"record":{"id":"0153074e30add448","repo":"quarkusio/quarkus","slug":"failed-to-instantiate-virtual-thread-binder-clas","errorCode":null,"errorMessage":"Failed to instantiate {{VIRTUAL_THREAD_BINDER_CLASSNAME}}","messagePattern":"Failed to instantiate (.+?)\\}","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/virtualthreads/VirtualThreadCollector.java","lineNumber":74,"sourceCode":"            }\n        } else {\n            this.tags = List.of();\n        }\n        this.binder = instantiated;\n    }\n\n    /**\n     * Use reflection to avoid calling a class touching Java 21+ APIs.\n     *\n     * @param tags the tags.\n     * @return the binder, {@code null} if the instantiation failed.\n     */\n    public MeterBinder instantiate(List<Tag> tags) {\n        try {\n            Class<?> clazz = Class.forName(VIRTUAL_THREAD_BINDER_CLASSNAME);\n            return (MeterBinder) clazz.getDeclaredConstructor(Iterable.class).newInstance(tags);\n        } catch (Exception e) {\n            throw new IllegalStateException(\"Failed to instantiate \" + VIRTUAL_THREAD_BINDER_CLASSNAME, e);\n        }\n    }\n\n    private Tag createTagFromEntry(String entry) {\n        String[] parts = entry.trim().split(\"=\");\n        if (parts.length == 2) {\n            return Tag.of(parts[0], parts[1]);\n        } else {\n            throw new IllegalStateException(\"Invalid tag: \" + entry + \" (expected key=value)\");\n        }\n    }\n\n    public MeterBinder getBinder() {\n        return binder;\n    }\n\n    public List<Tag> getTags() {\n        return tags;","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/micrometer/runtime/src/main/java/io/quarkus/micrometer/runtime/binder/virtualthreads/VirtualThreadCollector.java#L56-L92","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (application.properties on JDK 17, Micrometer without the binder)\nquarkus.micrometer.binder.virtual-threads.enabled=true\n// -> IllegalStateException: Failed to instantiate ...\n\n// after: run on JDK 21+ with a Micrometer that has the binder, or disable\n# quarkus.micrometer.binder.virtual-threads.enabled=false","handlingStrategy":"try-catch","validationCode":"String cls = \"io.micrometer.core.instrument.binder.jvm.VirtualThreadBinder\";\nboolean binderAvailable;\ntry {\n    Class.forName(cls);\n    binderAvailable = Runtime.version().feature() >= 21;\n} catch (ClassNotFoundException e) {\n    binderAvailable = false;\n}\n// only enable quarkus.micrometer.binder.virtual-threads.enabled if binderAvailable","typeGuard":"static boolean virtualThreadBinderSupported() {\n    try {\n        Class.forName(\"io.micrometer.core.instrument.binder.jvm.VirtualThreadBinder\");\n        return true;\n    } catch (ClassNotFoundException e) {\n        return false;\n    }\n}","tryCatchPattern":"try {\n    MeterBinder binder = collector.instantiate(tags);\n} catch (IllegalStateException e) {\n    log.warnf(\"Virtual thread metrics unavailable: %s (cause=%s)\", e.getMessage(), e.getCause());\n    // proceed without virtual thread metrics\n}","preventionTips":["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"],"tags":["quarkus","micrometer","virtual-threads","reflection","jdk-compatibility"],"backgroundTag":"reflective-class-instantiation-failed","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}