elastic/elasticsearch · error · UncheckedIOException

Error trying to read classpath resource: {}

Error message

Error trying to read classpath resource: {}

What it means

Thrown by GlobalBuildInfoPlugin.getResourceContents(String) when reading a classpath resource via GlobalBuildInfoPlugin.class.getResourceAsStream(resourcePath) fails with IOException. This method reads small text resources bundled in the build-tools-internal JAR, such as '/minimumGradleVersion' and '/minimumRuntimeVersion'. The IOException is wrapped in UncheckedIOException.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java:477

        return toolChainService.launcherFor(javaToolchainSpec -> javaToolchainSpec.getLanguageVersion().value(value))
            .map(launcher -> launcher.getMetadata().getInstallationPath().getAsFile());
    }

    public static String getResourceContents(String resourcePath) {
        try (
            BufferedReader reader = new BufferedReader(new InputStreamReader(GlobalBuildInfoPlugin.class.getResourceAsStream(resourcePath)))
        ) {
            StringBuilder b = new StringBuilder();
            for (String line = reader.readLine(); line != null; line = reader.readLine()) {
                if (b.length() != 0) {
                    b.append('\n');
                }
                b.append(line);
            }

            return b.toString();
        } catch (IOException e) {
            throw new UncheckedIOException("Error trying to read classpath resource: " + resourcePath, e);
        }
    }

    private static class ErrorTraceMetadataDetector implements JvmMetadataDetector {
        private final JvmMetadataDetector delegate;

        ErrorTraceMetadataDetector(JvmMetadataDetector delegate) {
            this.delegate = delegate;
        }

        @Override
        public JvmInstallationMetadata getMetadata(InstallationLocation installationLocation) {
            JvmInstallationMetadata metadata = delegate.getMetadata(installationLocation);
            if (metadata instanceof JvmInstallationMetadata.FailureInstallationMetadata) {
                throw new GradleException("Jvm Metadata cannot be resolved for " + metadata.getJavaHome().toString());
            }
            return metadata;
        }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Rebuild the build-tools-internal project: ./gradlew :build-tools-internal:build.
  2. Run a clean build to regenerate all JARs: ./gradlew clean build.
  3. Verify the resource exists in the JAR: jar tf build-tools-internal/build/libs/*.jar | grep minimumGradleVersion.
  4. If using a composite build, ensure the build-tools-internal project is properly included and its resources are generated.
Defensive patterns

Strategy: validation

Validate before calling

// Validate resource exists before reading
try (var is = GlobalBuildInfoPlugin.class.getResourceAsStream(resourcePath)) {
    if (is == null) {
        throw new FileNotFoundException("Classpath resource not found: " + resourcePath);
    }
    // safe to read
}

Prevention

When it happens

Trigger: getResourceAsStream returns a non-null stream (resource exists), but reading from it throws IOException. This is extremely rare in practice since classpath resources are typically packaged correctly. More commonly, if the resource is missing, getResourceAsStream returns null and the BufferedReader/InputStreamReader throws NullPointerException before IOException — which would not be caught by this handler.

Common situations: The build-tools-internal JAR is corrupted or incompletely built (resource is present in the manifest but truncated in the archive). A custom classloader interferes with resource loading. The resource is present but on a classpath source that becomes unavailable mid-read (e.g., a JAR on a network mount that disconnects).

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/44adbfab6475a16b. Report an issue: GitHub.