quarkusio/quarkus · error · IllegalArgumentException

The configuration ${clazz} is missing the @ConfigMapping ann

Error message

The configuration ${clazz} is missing the @ConfigMapping annotation

What it means

collectConfigRoots in BuildTimeConfigurationReader requires each config root class to be annotated with both @ConfigRoot and @ConfigMapping. When @ConfigRoot is present but the SmallRye @ConfigMapping annotation is missing, this IllegalArgumentException is thrown. @ConfigMapping is what turns the interface into a typed mapping of configuration properties.

Source

Thrown at core/deployment/src/main/java/io/quarkus/deployment/configuration/BuildTimeConfigurationReader.java:70

    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;
    }

    private final ClassLoader classLoader;

    private final List<ConfigClass> buildTimeMappings;
    private final List<ConfigClass> buildTimeRunTimeMappings;
    private final List<ConfigClass> runTimeMappings;
    private final List<ConfigClass> buildTimeVisibleMappings;
    private final Set<String> mappingsIgnorePaths;

    final ConfigTrackingInterceptor buildConfigTracker;

    /**

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add @ConfigMapping(prefix = "<prefix>") to the configuration interface alongside @ConfigRoot.
  2. Convert any remaining @ConfigItem fields into interface methods (the @ConfigMapping style).
  3. Verify the extension is not still registering a class-based config object where an interface is expected.

Example fix

// before
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface MyConfig { String name(); }

// after
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@ConfigMapping(prefix = "myapp")
public interface MyConfig { String name(); }
Defensive patterns

Strategy: validation

Validate before calling

MyConfig.class.isAnnotationPresent(ConfigRoot.class)
    && MyConfig.class.isAnnotationPresent(ConfigMapping.class);

Type guard

static boolean hasConfigMapping(Class<?> c) {
    return c.isAnnotationPresent(ConfigMapping.class);
}

Prevention

When it happens

Trigger: A configuration interface registered as a build-time config root has @ConfigRoot but no @ConfigMapping annotation, e.g. an older-style config interface migrated to the new @ConfigMapping model without adding the annotation.

Common situations: Migrating legacy @ConfigRoot/@ConfigItem classes to the @ConfigMapping model and only partially updating annotations; hand-writing config interfaces for extensions.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/496528c03be19104. Report an issue: GitHub.