{"record":{"id":"4b5d70d30ca8af07","repo":"quarkusio/quarkus","slug":"error-on-s-configuration-classes-with-configphas","errorCode":null,"errorMessage":"Error on %s: Configuration classes with ConfigPhase.RUN_TIME or ConfigPhase.BUILD_AND_RUNTIME_FIXED phases, must reside in the respective module.","messagePattern":"Error on (.+?): Configuration classes with ConfigPhase\\.RUN_TIME or ConfigPhase\\.BUILD_AND_RUNTIME_FIXED phases, must reside in the respective module\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java","lineNumber":224,"sourceCode":"            AnnotationMirror configDocEnumValue = annotations.get(Types.ANNOTATION_CONFIG_DOC_ENUM_VALUE);\n            if (configDocEnumValue != null) {\n                Map<String, Object> enumValueValues = utils.element().getAnnotationValues(configDocEnumValue);\n                explicitValue = (String) enumValueValues.get(\"value\");\n            }\n\n            enumConstants.put(enumElement.getSimpleName().toString(), new EnumConstant(explicitValue));\n        }\n\n        EnumDefinition enumDefinition = new EnumDefinition(enumTypeElement.getQualifiedName().toString(),\n                enumConstants);\n        configCollector.addResolvedEnum(enumDefinition);\n    }\n\n    private void validateRuntimeConfigOnDeploymentModules(ConfigPhase configPhase, TypeElement configRoot) {\n        if (configPhase.equals(ConfigPhase.RUN_TIME) || configPhase.equals(ConfigPhase.BUILD_AND_RUN_TIME_FIXED)) {\n            ExtensionModule.ExtensionModuleType type = config.getExtensionModule().type();\n            if (type.equals(ExtensionModule.ExtensionModuleType.DEPLOYMENT)) {\n                throw new IllegalStateException(String.format(\n                        \"Error on %s: Configuration classes with ConfigPhase.RUN_TIME or \" +\n                                \"ConfigPhase.BUILD_AND_RUNTIME_FIXED phases, must reside in the respective module.\",\n                        configRoot.getSimpleName().toString()));\n            }\n        }\n    }\n\n    private void handleCommonPropertyAnnotations(DiscoveryConfigProperty.Builder builder,\n            Map<String, AnnotationMirror> propertyAnnotations, ResolvedType resolvedType, String sourceElementName) {\n\n        AnnotationMirror deprecatedAnnotation = propertyAnnotations.get(Deprecated.class.getName());\n        if (deprecatedAnnotation != null) {\n            String since = (String) utils.element().getAnnotationValues(deprecatedAnnotation).get(\"since\");\n            // TODO add more information about the deprecation, typically the reason and a replacement\n            builder.deprecated(since, null, null);\n        }\n\n        AnnotationMirror configDocSectionAnnotation = propertyAnnotations.get(Types.ANNOTATION_CONFIG_DOC_SECTION);","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/scanner/ConfigMappingListener.java#L206-L242","documentation":"The Quarkus annotation processor enforces that configuration classes declared with ConfigPhase.RUN_TIME or ConfigPhase.BUILD_AND_RUN_TIME_FIXED live in the runtime module, not the deployment module. Runtime-phase config is needed by application runtime code, and deployment-only artifacts must not contain it. When such a config root is found in a module whose ExtensionModule type is DEPLOYMENT, validation throws this IllegalStateException.","triggerScenarios":"Compiling a deployment (quarkus-<ext>-deployment) module that contains a class annotated @ConfigRoot(phase = ConfigPhase.RUN_TIME) or ConfigPhase.BUILD_AND_RUN_TIME_FIXED, detected by validateRuntimeConfigOnDeploymentModules during config scanning.","commonSituations":"Creating a new runtime config interface but placing the file in the deployment module by accident; moving classes between modules during a refactor; generating config classes into the wrong source root.","solutions":["Move the config class from the deployment module (extensions/<name>/deployment) to the runtime module (extensions/<name>/runtime).","Change the @ConfigRoot phase to BUILD_TIME only if the config genuinely is build-time-only and consumed solely at deployment.","Update package names to the runtime module's package (io.quarkus.<ext>.runtime...) and fix imports/dependents.","Rebuild the extension with ./mvnw install -f extensions/<name>/ to re-run validation."],"exampleFix":"// before (deployment module)\n// extensions/foo/deployment/src/main/java/io/quarkus/foo/deployment/FooConfig.java\n@ConfigRoot(phase = ConfigPhase.RUN_TIME)\n@ConfigMapping(prefix = \"quarkus.foo\")\npublic interface FooConfig { }\n// after (runtime module)\n// extensions/foo/runtime/src/main/java/io/quarkus/foo/runtime/FooConfig.java\n@ConfigRoot(phase = ConfigPhase.RUN_TIME)\n@ConfigMapping(prefix = \"quarkus.foo\")\npublic interface FooConfig { }","handlingStrategy":"validation","validationCode":"Path src = deploymentModule.resolve(\"src/main/java\");\ntry (Stream<Path> s = Files.walk(src)) {\n    List<Path> bad = s.filter(p -> {\n        try {\n            return Files.readString(p).contains(\"ConfigPhase.RUN_TIME\");\n        } catch (IOException e) { return false; }\n    }).toList();\n    if (!bad.isEmpty()) throw new IllegalStateException(\"Runtime config in deployment module: \" + bad);\n}","typeGuard":"boolean isRuntimeConfigInWrongModule(TypeElement configRoot, ExtensionModule module) {\n    return (configRoot.getAnnotation(ConfigRoot.class) != null)\n        && module.type() == ExtensionModule.ExtensionModuleType.DEPLOYMENT;\n}","tryCatchPattern":"try {\n    buildExtension();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"must reside in the respective module\")) {\n        moveConfigClassToRuntimeModule();\n    } else throw e;\n}","preventionTips":["Runtime and RUN_TIME-fixed config classes always live in extensions/<name>/runtime.","Deployment modules should only contain processors, build steps, and recorders.","Follow the standard extension archetype layout when scaffolding new extensions.","Review module placement in PRs that move config files between modules."],"tags":["quarkus","annotation-processor","config","module-structure"],"backgroundTag":"runtime-config-in-wrong-module","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}