quarkusio/quarkus · error · IllegalStateException

We found a @ConfigRoot without a corresponding @ConfigMappin

Error message

We found a @ConfigRoot without a corresponding @ConfigMapping annotation in: ${configRoot}. Make sure your configuration interfaces are annotated with @ConfigMapping.

What it means

checkConfigRootAnnotationConsistency enforces that every class annotated with @ConfigRoot is also annotated with @ConfigMapping. Quarkus removed the legacy @ConfigRoot-only configuration class style; a root without @ConfigMapping cannot be processed and documentation scanning aborts with this message naming the offending class.

Source

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

                if (discoveryRootElement != null) {
                    throw new IllegalStateException("Multiple listeners returned discovery root elements for: " +
                            discoveryRootElement.getQualifiedName());
                }

                discoveryRootElement = discoveryRootElementCandidate.get();
            }
        }

        if (discoveryRootElement == null) {
            throw new IllegalStateException("No listeners returned a discovery root element");
        }

        return discoveryRootElement;
    }

    private void checkConfigRootAnnotationConsistency(TypeElement configRoot) {
        if (!utils.element().isAnnotationPresent(configRoot, Types.ANNOTATION_CONFIG_MAPPING)) {
            throw new IllegalStateException(
                    "We found a @ConfigRoot without a corresponding @ConfigMapping annotation in: " + configRoot + "."
                            + " Make sure your configuration interfaces are annotated with @ConfigMapping.");
        }
    }

    private void debug(String debug, Element element) {
        if (!config.isDebug()) {
            return;
        }

        utils.processingEnv().getMessager().printMessage(Kind.NOTE, "[" + element.getSimpleName() + "] " + debug);
    }
}

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add @ConfigMapping (with the prefix) to the named class; keep @ConfigRoot only for phase declaration.
  2. Move the prefix from @ConfigRoot's (removed) prefix attribute into @ConfigMapping(prefix = "...").
  3. Regenerate the config class with the Quarkus config mapping code style if migrating.
  4. Update outdated example/tutorial code to the current Quarkus configuration style.

Example fix

// before (legacy)
@ConfigRoot(prefix = "myapp", phase = ConfigPhase.RUN_TIME)
public interface MyAppConfig { String name(); }

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

Strategy: validation

Validate before calling

// fail fast in an ArchUnit/unit test during migration
for (Class<?> c : allConfigClasses) {
    if (c.isAnnotationPresent(ConfigRoot.class)
            && !c.isAnnotationPresent(ConfigMapping.class))
        throw new IllegalStateException(c + " needs @ConfigMapping");
}

Type guard

static boolean hasRequiredAnnotations(Class<?> c) {
    return !c.isAnnotationPresent(ConfigRoot.class)
        || c.isAnnotationPresent(ConfigMapping.class);
}

Prevention

When it happens

Trigger: Compiling a class annotated with @ConfigRoot (any phase/prefix) whose declaration lacks @ConfigMapping — typically after upgrading from an older Quarkus where @ConfigRoot(prefix=..., phase=...) alone was valid.

Common situations: Migrating extensions or applications from pre-@ConfigMapping-era Quarkus; copied example code from outdated blogs/docs; custom configuration interfaces written against an old Quarkus version.

Related errors


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