{"record":{"id":"1425de4bd0ecfb81","repo":"elastic/elasticsearch","slug":"classname-can-only-be-applied-to-the-root-projec-1425de","errorCode":null,"errorMessage":"{className} can only be applied to the root project.","messagePattern":"(.+?) can only be applied to the root project\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java","lineNumber":112,"sourceCode":"    @Inject\n    public GlobalBuildInfoPlugin(\n        ObjectFactory objectFactory,\n        JavaInstallationRegistry javaInstallationRegistry,\n        JvmMetadataDetector metadataDetector,\n        ProviderFactory providers,\n        BuildFeatures buildFeatures\n    ) {\n        this.objectFactory = objectFactory;\n        this.javaInstallationRegistry = javaInstallationRegistry;\n        this.metadataDetector = new ErrorTraceMetadataDetector(metadataDetector);\n        this.providers = providers;\n        this.buildFeatures = buildFeatures;\n    }\n\n    @Override\n    public void apply(Project project) {\n        if (project != project.getRootProject()) {\n            throw new IllegalStateException(this.getClass().getName() + \" can only be applied to the root project.\");\n        }\n        this.project = project;\n        project.getPlugins().apply(JvmToolchainsPlugin.class);\n        project.getPlugins().apply(JdkDownloadPlugin.class);\n        project.getPlugins().apply(VersionPropertiesPlugin.class);\n        Provider<GitInfo> gitInfo = project.getPlugins().apply(GitInfoPlugin.class).getGitInfo();\n\n        toolChainService = project.getExtensions().getByType(JavaToolchainService.class);\n        GradleVersion minimumGradleVersion = GradleVersion.version(getResourceContents(\"/minimumGradleVersion\"));\n        if (GradleVersion.current().compareTo(minimumGradleVersion) < 0) {\n            throw new GradleException(\"Gradle \" + minimumGradleVersion.getVersion() + \"+ is required\");\n        }\n\n        Properties versionProperties = (Properties) project.getExtensions().getByName(VERSIONS_EXT);\n        JavaVersion minimumCompilerVersion = JavaVersion.toVersion(versionProperties.get(\"minimumCompilerJava\"));\n        JavaVersion minimumRuntimeVersion = JavaVersion.toVersion(versionProperties.get(\"minimumRuntimeJava\"));\n        Version elasticsearchVersionProperty = Version.fromString(versionProperties.getProperty(\"elasticsearch\"));\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java#L94-L130","documentation":"Thrown by GlobalBuildInfoPlugin.apply(Project) when the plugin is applied to a Gradle subproject instead of the root project. GlobalBuildInfoPlugin is the central build-info plugin that registers the Java toolchain, JDK download, version properties, git info, and build parameters extensions. These are singletons that must exist once at the root. The guard is an identity check: project != project.getRootProject().","triggerScenarios":"Applying GlobalBuildInfoPlugin (directly or transitively via another convention plugin) to a non-root project. Since DockerSupportPlugin and other root-level plugins apply GlobalBuildInfoPlugin, transitively applying any of them to a subproject triggers this.","commonSituations":"A convention plugin in build-conventions or build-tools-internal that bundles GlobalBuildInfoPlugin is applied per-subproject. A developer adds `id('elasticsearch.global-build-info')` to a subproject's build.gradle. A composite build setup causes the plugin to be applied to an included build's subproject.","solutions":["Apply GlobalBuildInfoPlugin only in the root build.gradle.","If applying through a convention plugin, guard the convention plugin itself to only apply to the root project.","Subprojects should access build info (toolchain, version properties) via the root project's extensions, not by re-applying the plugin."],"exampleFix":"// before (subproject build.gradle)\napply plugin: 'elasticsearch.global-build-info'\n\n// after (root build.gradle only)\napply plugin: 'elasticsearch.global-build-info'\n// subprojects consume extensions registered at root","handlingStrategy":"validation","validationCode":"// In a convention plugin, validate before applying\nif (project == project.getRootProject()) {\n    project.getPlugins().apply(GlobalBuildInfoPlugin.class);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply GlobalBuildInfoPlugin only from the root build.gradle or settings.gradle.","Subprojects should consume build info extensions from the root project.","Document root-only constraint in the plugin class Javadoc."],"tags":["gradle","build-infrastructure","plugin-configuration","java-toolchain"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}