elastic/elasticsearch · error · UncheckedIOException

Failed to load {EXTERNAL_SOURCES_CONFIG}

Error message

Failed to load {EXTERNAL_SOURCES_CONFIG}

What it means

Wrapped as UncheckedIOException from ReleaseToolsPlugin.loadExternalSources() when the classpath resource named by EXTERNAL_SOURCES_CONFIG exists but cannot be read or parsed as YAML into List<ExternalChangelogSource>. A missing resource is NOT an error (returns List.of()); only an IOException during read/parse triggers this.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/release/ReleaseToolsPlugin.java:133

        project.getTasks().register("pruneChangelogs", PruneChangelogsTask.class).configure(task -> {
            task.setGroup("Documentation");
            task.setDescription("Removes changelog files that have been used in a previous release");
            task.setChangelogs(yamlFiles);
        });

        project.getTasks().named("precommit").configure(task -> task.dependsOn(validateChangelogsTask));
    }

    private static List<BundleChangelogsTask.ExternalChangelogSource> loadExternalSources() {
        try (InputStream is = ReleaseToolsPlugin.class.getClassLoader().getResourceAsStream(EXTERNAL_SOURCES_CONFIG)) {
            if (is == null) {
                return List.of();
            }
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            return mapper.readValue(is, new TypeReference<>() {});
        } catch (IOException e) {
            throw new UncheckedIOException("Failed to load " + EXTERNAL_SOURCES_CONFIG, e);
        }
    }
}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Open the resource named by EXTERNAL_SOURCES_CONFIG (search build-tools-internal src/main/resources) and validate it as well-formed YAML matching the ExternalChangelogSource shape.
  2. Run the YAML through an external parser (e.g. python yaml.safe_load) to pinpoint the offending line, then fix it.
  3. If the file is genuinely optional, confirm the resource is absent (which returns List.of()) rather than present-but-broken.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the resource parses before the build runs
try (InputStream is = ReleaseToolsPlugin.class.getClassLoader().getResourceAsStream(EXTERNAL_SOURCES_CONFIG)) {
    if (is != null) {
        new ObjectMapper(new YAMLFactory()).readValue(is, new TypeReference<List<BundleChangelogsTask.ExternalChangelogSource>>() {});
    }
} catch (IOException e) {
    throw new IllegalStateException("External sources config is malformed: " + e.getMessage(), e);
}

Try / catch

try { loadExternalSources(); } catch (UncheckedIOException e) { log.error("Fix the YAML at {} on the classpath", EXTERNAL_SOURCES_CONFIG); throw e; }

Prevention

When it happens

Trigger: The external-sources YAML config file is present on the plugin classpath but is malformed YAML, has a schema that does not match ExternalChangelogSource, or the stream throws IOException mid-read.

Common situations: Someone edits the bundled external changelog sources YAML and introduces a syntax error; the Jackson ObjectMapper / YAMLFactory version is upgraded and becomes stricter on a previously-tolerated construct; the resource is packaged but truncated.

Related errors


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