quarkusio/quarkus · error · IllegalStateException
Either @ConfigRoot or @ConfigMapping is missing on ${configR
Error message
Either @ConfigRoot or @ConfigMapping is missing on ${configRoot} What it means
This IllegalStateException is thrown by the Quarkus annotation processor while scanning @ConfigRoot-annotated classes during config documentation generation. Every config root class must carry both the Quarkus @ConfigRoot (or legacy @ConfigRoot) annotation and MicroProfile @ConfigMapping; if either annotation mirror cannot be resolved on the element, processing aborts. It indicates a malformed or inconsistent configuration class definition in an extension.
Source
Thrown at core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java:74
configRootAnnotation = annotationMirror;
continue;
}
if (annotationName.equals(Types.ANNOTATION_CONFIG_MAPPING)) {
configMappingAnnotion = annotationMirror;
continue;
}
if (annotationName.equals(Types.ANNOTATION_CONFIG_DOC_PREFIX)) {
configDocPrefixAnnotation = annotationMirror;
continue;
}
if (annotationName.equals(Types.ANNOTATION_CONFIG_DOC_FILE_NAME)) {
configDocFileNameAnnotation = annotationMirror;
continue;
}
}
if (configRootAnnotation == null || configMappingAnnotion == null) {
throw new IllegalStateException("Either @ConfigRoot or @ConfigMapping is missing on " + configRoot);
}
final Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = configRootAnnotation
.getElementValues();
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : elementValues.entrySet()) {
if ("phase()".equals(entry.getKey().toString())) {
configPhase = ConfigPhase.valueOf(entry.getValue().getValue().toString());
}
}
validateRuntimeConfigOnDeploymentModules(configPhase, configRoot);
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : configMappingAnnotion.getElementValues()
.entrySet()) {
if ("prefix()".equals(entry.getKey().toString())) {
prefix = entry.getValue().getValue().toString();
}
}View on GitHub (pinned to e1c734241f)
Solutions
- Add the missing annotation: annotate the class with both @ConfigMapping and @ConfigRoot (with phase, e.g. @ConfigRoot(phase = ConfigPhase.BUILD_TIME)).
- If the class is legacy-style, either add @ConfigMapping or convert it fully to the @ConfigMapping model per current Quarkus conventions.
- Verify the annotations are on the same TypeElement the processor scans (not a superclass) and are runtime-retained source-visible as required.
- Rebuild the extension module with ./mvnw install to re-run annotation processing and confirm the fix.
Example fix
// before
@ConfigMapping(prefix = "quarkus.my-ext")
public interface MyExtConfig { }
// after
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
@ConfigMapping(prefix = "quarkus.my-ext")
public interface MyExtConfig { } Defensive patterns
Strategy: validation
Validate before calling
if (!typeElement.getAnnotationMirrors().stream()
.map(a -> a.getAnnotationType().toString())
.anyMatch(n -> n.endsWith("ConfigRoot"))) {
throw new IllegalStateException(typeElement + " must be annotated with @ConfigRoot");
} Type guard
boolean hasAnnotation(TypeElement e, String simpleName) {
return e.getAnnotationMirrors().stream()
.anyMatch(a -> a.getAnnotationType().asElement().getSimpleName()
.contentEquals(simpleName));
} Try / catch
try {
compile(extensionModule);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("@ConfigRoot or @ConfigMapping is missing")) {
fixConfigAnnotations(e);
} else throw e;
} Prevention
- Always pair @ConfigMapping with @ConfigRoot on Quarkus config classes.
- Copy config class templates from existing extensions rather than writing from scratch.
- Run the extension build locally before pushing so annotation processing errors surface early.
- When migrating off legacy config classes, update both annotations in the same commit.
When it happens
Trigger: Compiling an extension whose config class is annotated with @ConfigMapping but lacks @ConfigRoot, or vice versa, or when the annotation is present via inheritance/indirection such that the annotation processor cannot find its mirror on the TypeElement passed to onConfigRoot.
Common situations: Adding a new @ConfigMapping interface to an extension and forgetting the Quarkus @ConfigRoot annotation; upgrading Quarkus and migrating off legacy config classes; copy-pasting a config class and dropping one annotation.
Related errors
- The supplied 'main-class' value of '${mainClassName}' does n
- Starting with Quarkus 3.25, legacy config classes (deprecate
- Error on %s: Configuration classes with ConfigPhase.RUN_TIME
- Unable to find javadoc for config item ${enclosingElement} $
- Unable to load the config property type: ${className}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/2fd3ec9e228a39d1.
Report an issue: GitHub.