{"record":{"id":"f5c5d840471e6bc1","repo":"quarkusio/quarkus","slug":"unable-to-scan-config-root-configroot","errorCode":null,"errorMessage":"Unable to scan config root: ${configRoot}","messagePattern":"Unable to scan config root: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigAnnotationScanner.java","lineNumber":115,"sourceCode":"\n            final PackageElement pkg = utils.element().getPackageOf(configRoot);\n            if (pkg == null) {\n                utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR,\n                        \"Element \" + configRoot + \" has no enclosing package\");\n                continue;\n            }\n\n            if (isConfigRootAlreadyHandled(configRoot)) {\n                continue;\n            }\n\n            debug(\"Detected config root: \" + configRoot, configRoot);\n\n            try {\n                DiscoveryConfigRoot discoveryConfigRoot = applyRootListeners(l -> l.onConfigRoot(configRoot));\n                scanElement(configRootListeners, discoveryConfigRoot, configRoot);\n            } catch (Exception e) {\n                throw new IllegalStateException(\"Unable to scan config root: \" + configRoot, e);\n            }\n        }\n    }\n\n    /**\n     * In this case, we will just apply the Javadoc listeners to collect Javadoc.\n     */\n    public void scanConfigMappingsWithoutConfigRoot(RoundEnvironment roundEnv, TypeElement annotation) {\n        for (TypeElement configMappingWithoutConfigRoot : typesIn(roundEnv.getElementsAnnotatedWith(annotation))) {\n            if (utils.element().isAnnotationPresent(configMappingWithoutConfigRoot, Types.ANNOTATION_CONFIG_ROOT)) {\n                continue;\n            }\n\n            final PackageElement pkg = utils.element().getPackageOf(configMappingWithoutConfigRoot);\n            if (pkg == null) {\n                utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR,\n                        \"Element \" + configMappingWithoutConfigRoot + \" has no enclosing package\");\n                continue;","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigAnnotationScanner.java#L97-L133","documentation":"The processor failed while scanning a class annotated with @ConfigRoot. After checkConfigRootAnnotationConsistency, listeners discover the root's metadata and the scanner walks its members; any exception is wrapped in this IllegalStateException naming the config root class.","triggerScenarios":"Compiling a @ConfigRoot class where listener processing or scanElement fails: invalid member types, unregistered enums referenced by properties, unresolvable nested config groups, or a conflicting/unsupported @ConfigRoot declaration (bad phase, prefix, or missing @ConfigMapping).","commonSituations":"Extension authors developing custom configuration classes; a config root referencing an enum or group the collector never registered; build order issues where referenced types are not yet compiled; Quarkus version mismatch between the annotation processor and SmallRye config APIs.","solutions":["Inspect the 'Caused by' exception for the root cause (often 'Could not find registered EnumDefinition' or a type-resolution error).","Ensure the class is annotated with @ConfigMapping in addition to @ConfigRoot and has a valid prefix/phase.","Fix member types: all properties must be supported config types with registered enums.","Run a clean build so referenced types resolve during annotation processing.","Minimize the failing config root to isolate the offending member; report a Quarkus bug if the class looks standard."],"exampleFix":"// before\n@ConfigRoot(prefix = \"my-ext\", phase = ConfigPhase.BUILD_TIME)\npublic interface MyExtConfig { ... } // scan fails\n\n// after\n@ConfigMapping(prefix = \"my-ext\")\n@ConfigRoot(phase = ConfigPhase.BUILD_TIME)\npublic interface MyExtConfig { ... }","handlingStrategy":"validation","validationCode":"// verify each config root before build\nif (!myConfigClass.isAnnotationPresent(ConfigMapping.class)\n        || !myConfigClass.isAnnotationPresent(ConfigRoot.class))\n    throw new IllegalStateException(\"Config root must have both @ConfigMapping and @ConfigRoot\");","typeGuard":"static boolean isValidConfigRoot(Class<?> c) {\n    return c.isAnnotationPresent(ConfigRoot.class)\n        && c.isAnnotationPresent(ConfigMapping.class)\n        && c.isInterface();\n}","tryCatchPattern":"try {\n    scanner.scanConfigRoots(roundEnv, annotation);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Unable to scan config root:\")) {\n        log.error(\"Check Caused by for the offending member in \" + e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Always pair @ConfigRoot with @ConfigMapping and put the prefix on @ConfigMapping.","Use only supported property types; register enums properly.","Clean build after any Quarkus upgrade.","Follow the working-with-config conventions when authoring roots."],"tags":["quarkus","annotation-processing","config-root","build","scanner"],"backgroundTag":"annotation-scanning-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"}