quarkusio/quarkus · error · IllegalStateException

Unable to scan config root: ${configRoot}

Error message

Unable to scan config root: ${configRoot}

What it means

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.

Source

Thrown at core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigAnnotationScanner.java:115

            final PackageElement pkg = utils.element().getPackageOf(configRoot);
            if (pkg == null) {
                utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR,
                        "Element " + configRoot + " has no enclosing package");
                continue;
            }

            if (isConfigRootAlreadyHandled(configRoot)) {
                continue;
            }

            debug("Detected config root: " + configRoot, configRoot);

            try {
                DiscoveryConfigRoot discoveryConfigRoot = applyRootListeners(l -> l.onConfigRoot(configRoot));
                scanElement(configRootListeners, discoveryConfigRoot, configRoot);
            } catch (Exception e) {
                throw new IllegalStateException("Unable to scan config root: " + configRoot, e);
            }
        }
    }

    /**
     * In this case, we will just apply the Javadoc listeners to collect Javadoc.
     */
    public void scanConfigMappingsWithoutConfigRoot(RoundEnvironment roundEnv, TypeElement annotation) {
        for (TypeElement configMappingWithoutConfigRoot : typesIn(roundEnv.getElementsAnnotatedWith(annotation))) {
            if (utils.element().isAnnotationPresent(configMappingWithoutConfigRoot, Types.ANNOTATION_CONFIG_ROOT)) {
                continue;
            }

            final PackageElement pkg = utils.element().getPackageOf(configMappingWithoutConfigRoot);
            if (pkg == null) {
                utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR,
                        "Element " + configMappingWithoutConfigRoot + " has no enclosing package");
                continue;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Inspect the 'Caused by' exception for the root cause (often 'Could not find registered EnumDefinition' or a type-resolution error).
  2. Ensure the class is annotated with @ConfigMapping in addition to @ConfigRoot and has a valid prefix/phase.
  3. Fix member types: all properties must be supported config types with registered enums.
  4. Run a clean build so referenced types resolve during annotation processing.
  5. Minimize the failing config root to isolate the offending member; report a Quarkus bug if the class looks standard.

Example fix

// before
@ConfigRoot(prefix = "my-ext", phase = ConfigPhase.BUILD_TIME)
public interface MyExtConfig { ... } // scan fails

// after
@ConfigMapping(prefix = "my-ext")
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface MyExtConfig { ... }
Defensive patterns

Strategy: validation

Validate before calling

// verify each config root before build
if (!myConfigClass.isAnnotationPresent(ConfigMapping.class)
        || !myConfigClass.isAnnotationPresent(ConfigRoot.class))
    throw new IllegalStateException("Config root must have both @ConfigMapping and @ConfigRoot");

Type guard

static boolean isValidConfigRoot(Class<?> c) {
    return c.isAnnotationPresent(ConfigRoot.class)
        && c.isAnnotationPresent(ConfigMapping.class)
        && c.isInterface();
}

Try / catch

try {
    scanner.scanConfigRoots(roundEnv, annotation);
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Unable to scan config root:")) {
        log.error("Check Caused by for the offending member in " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


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