quarkusio/quarkus · error · IllegalArgumentException
The configuration ${clazz} must be an interface annotated wi
Error message
The configuration ${clazz} must be an interface annotated with @ConfigRoot and @ConfigMapping What it means
BuildTimeConfigurationReader.collectConfigRoots loads classes listed in the generated config-roots list and requires each to be an interface annotated with @ConfigRoot (and @ConfigMapping). A non-interface class in that list violates the configuration model contract, so IllegalArgumentException is thrown at build start.
Source
Thrown at core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java:59
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.config.SmallRyeConfigBuilder;
import io.smallrye.config.SmallRyeConfigBuilderCustomizer;
import io.smallrye.config.SysPropConfigSource;
import io.smallrye.config.common.AbstractConfigSource;
/**
* A configuration reader.
*/
public final class BuildTimeConfigurationReader {
private static final String CONFIG_ROOTS_LIST = "META-INF/quarkus-config-roots.list";
private static List<Class<?>> collectConfigRoots(ClassLoader classLoader) throws IOException, ClassNotFoundException {
Assert.checkNotNullParam("classLoader", classLoader);
// populate with all known types
List<Class<?>> roots = new ArrayList<>();
for (Class<?> clazz : ServiceUtil.classesNamedIn(classLoader, CONFIG_ROOTS_LIST)) {
if (!clazz.isInterface()) {
throw new IllegalArgumentException(
"The configuration " + clazz + " must be an interface annotated with @ConfigRoot and @ConfigMapping");
}
ConfigRoot configRoot = clazz.getAnnotation(ConfigRoot.class);
if (configRoot == null) {
throw new IllegalArgumentException("The configuration " + clazz + " is missing the @ConfigRoot annotation");
}
ConfigMapping configMapping = clazz.getAnnotation(ConfigMapping.class);
if (configMapping == null) {
throw new IllegalArgumentException("The configuration " + clazz + " is missing the @ConfigMapping annotation");
}
roots.add(clazz);
}
return roots;
}
View on GitHub (pinned to e1c734241f)
Solutions
- Convert the config root to a Java interface annotated with @ConfigMapping and @ConfigRoot
- Remove any leftover legacy @ConfigRoot/@ConfigItem class-based configuration
- Rebuild so the generated config-roots service file no longer lists the offending class
Example fix
// before
@ConfigRoot(name="app")
public class AppConfig { @ConfigItem public String name; }
// after
@ConfigRoot(name="app")
@ConfigMapping(prefix="app")
public interface AppConfig { String name(); } Defensive patterns
Strategy: validation
Validate before calling
Class<?> c = ...;
if (!c.isInterface() || c.getAnnotation(ConfigRoot.class) == null || c.getAnnotation(ConfigMapping.class) == null)
throw new IllegalStateException(c + " must be an @ConfigMapping interface annotated with @ConfigRoot"); Type guard
boolean isConfigRootInterface(Class<?> c) { return c.isInterface() && c.isAnnotationPresent(ConfigRoot.class); } Try / catch
try { new BuildTimeConfigurationReader(classLoader); } catch (IllegalArgumentException e) { log.error("Bad config root registration", e); throw e; } Prevention
- Define all configuration roots as interfaces with @ConfigMapping (plus @ConfigRoot in extensions)
- Never register legacy @ConfigRoot class-based configuration
- Rebuild extensions after Quarkus upgrades so generated config-roots lists stay current
When it happens
Trigger: A class implementing/registered as a config root that is a class or enum rather than an interface; stale generated CONFIG_ROOTS_LIST service file referencing a legacy class-based config root.
Common situations: Migrating from legacy @ConfigRoot class + @ConfigItem style (removed in modern Quarkus) to @ConfigMapping interfaces; a custom extension still registering an old-style config class.
Related errors
- The supplied 'main-class' value of '${mainClassName}' does n
- Starting with Quarkus 3.25, legacy config classes (deprecate
- Either @ConfigRoot or @ConfigMapping is missing on ${configR
- Unable to load the config property type: ${className}
- Annotation '%s' placed on '%s' specifies no 'acr' value
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5f3ed12fd5d7c810.
Report an issue: GitHub.