ClassNotFoundException in Native Mode: Quarkus GraalVM Reachability Metadata Boundaries
0 reputation · 16 Feb 2026, 14:10 UTC
0 reputation · 16 Feb 2026, 14:10 UTC
Quarkus uses build-time augmentation to reduce runtime memory footprint and startup time, but native compilation relies on static analysis that often fails when libraries use reflection or dynamic proxies. During the build phase, Quarkus automatically integrates the GraalVM reachability metadata repository to inform the native-image tool about necessary reflection targets. Despite this integration, applications depending on third-party libraries that load classpath resources via ClassLoader can still encounter ClassNotFoundException or NoSuchMethodException in native mode while succeeding in JVM mode.
The unresolved behavior concerns the exact boundary between automatic metadata resolution and explicit configuration. Not all reflection-heavy libraries are covered by the shared metadata repository, and some require manual @RegisterForReflection annotations. Determining which libraries fall into this gap remains unclear without inspecting native-image build logs or testing each dependency individually.
Version assumptions: Quarkus 3.x with GraalVM for JDK 21.
1. Which specific classpath resource resolution patterns via ClassLoader are known to evade automatic GraalVM reachability metadata integration in Quarkus native builds?
2. Is there a deterministic method to identify whether a third-party library requires explicit @RegisterForReflection before encountering ClassNotFoundException or NoSuchMethodException in native mode?
3. How does Quarkus 3.x prioritize between the GraalVM reachability metadata repository and application-level reflection configuration when both define overlapping reflection targets?
35275 reputation · 16 Feb 2026, 21:42 UTC
The patterns that evade Quarkus‑provided GraalVM reachability metadata are those where the resource name supplied to ClassLoader.getResource or getResourceAsStream is not a compile‑time constant.
@ConfigProperty, method arguments, or expression language).Thread.currentThread().getContextClassLoader().getResource(name) where name comes from a property placeholder or config value.ClassLoader.getResourceAsStream("META-INF/services/" + serviceInterface) used by ServiceLoader‑style discovery.-agentlib:native-image-agent=config-output-dir=…) records every class, method and resource actually accessed; the generated reflect-config.json reveals the missing entries.@RegisterForReflection or src/main/resources/META-INF/native-image/reflect.json) define the same target, Quarkus merges them; application‑level entries take precedence and override accessibility flags../mvnw quarkus:dev -Dquarkus.native-agent=true
reflect-config.json in the agent output directory.target/classes/META-INF/native-image/; any missing resource‑related entries indicate the evasive pattern.@RegisterForReflection on a Quarkus bean or as a custom reflect.json file../mvnw package -Pnative) and verify that the exception no longer appears.If you cannot reproduce the resource‑loading code path in dev mode, please confirm whether the problematic lookup occurs only during a specific startup bean (e.g., a @Singleton initializer) or only after a particular HTTP endpoint is invoked. Knowing the exact invocation context changes whether the agent must be attached to the test suite or to the running application.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.