elastic/elasticsearch · error · RuntimeException
Unable to locate {} on build classpath.
Error message
Unable to locate {} on build classpath. What it means
ReaperService.locateReaperJar() throws RuntimeException (internal mode) when the URL of the reaper class resource does not match the REAPER_JAR_PATH_PATTERN regex `file:(.*)!/org/elasticsearch/gradle/reaper/Reaper.class`. In internal mode the build expects the class to live inside a JAR on the runtime classpath (a `file:...!/...` jar URL); a mismatch means the class is loaded from an exploded directory, a different protocol, or the JAR isn't where the build expects it.
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/ReaperService.java:138
}
}
private Path logFilePath() {
return getParameters().getInputDir().get().getAsFile().toPath().resolve("reaper.log");
}
private Path locateReaperJar() {
if (getParameters().getInternal()) {
// when running inside the Elasticsearch build just pull find the jar in the runtime classpath
URL main = this.getClass().getClassLoader().getResource(REAPER_CLASS);
String mainPath = main.getFile();
Matcher matcher = REAPER_JAR_PATH_PATTERN.matcher(mainPath);
if (matcher.matches()) {
String path = matcher.group(1);
return Path.of(OS.<String>conditional().onWindows(() -> path.substring(1)).onUnix(() -> path).supply());
} else {
throw new RuntimeException("Unable to locate " + REAPER_CLASS + " on build classpath.");
}
} else {
// copy the reaper jar
Path jarPath = getParameters().getBuildDir().get().getAsFile().toPath().resolve("reaper").resolve("reaper.jar");
try {
Files.createDirectories(jarPath.getParent());
} catch (IOException e) {
throw new UncheckedIOException("Unable to create reaper JAR output directory " + jarPath.getParent(), e);
}
try (
OutputStream out = Files.newOutputStream(jarPath);
InputStream jarInput = this.getClass().getResourceAsStream("/META-INF/reaper.jar");
) {
logger.info("Copying reaper.jar...");
jarInput.transferTo(out);
} catch (IOException e) {
throw new UncheckedIOException(e);View on GitHub (pinned to db6a809a66)
Solutions
- Ensure build-tools is packaged as a JAR on the runtime classpath (run the normal Gradle build, not an IDE exploded run).
- If main == null (resource missing), the build-tools JAR is incomplete — rebuild it with the reaper classes included.
- For non-internal contexts, use Params.internal = false so the JAR is copied from /META-INF/reaper.jar instead of located on the classpath.
Defensive patterns
Strategy: try-catch
Validate before calling
URL main = ReaperService.class.getClassLoader().getResource("org/elasticsearch/gradle/reaper/Reaper.class");
if (main == null || !main.getFile().contains("!/.")) {
throw new IllegalStateException("Reaper class not packaged in a JAR; rebuild build-tools");
} Try / catch
try { Path jar = reaperService.locateReaperJar(); } catch (RuntimeException e) { /* ensure build-tools JAR contains reaper classes */ throw e; } Prevention
- Run the normal Gradle build so build-tools is packaged as a JAR.
- Avoid IDE exploded-classpath runs that bypass JAR packaging.
- Use Params.internal = false to copy the JAR from /META-INF/reaper.jar when classpath layout is uncertain.
When it happens
Trigger: Running build-tools in internal mode (Params.internal = true) where getClass().getClassLoader().getResource(REAPER_CLASS) returns a URL that is not a JAR-entry URL — e.g., the class is on an exploded classpath (IDE run configs, some test harnesses), the resource is missing (main == null → NPE on main.getFile() would actually fire first), or the URL uses a non-file protocol.
Common situations: Running build-tools from an IDE with exploded class output instead of the packaged JAR; a broken build-tools JAR that omits the reaper classes; a custom classloader that returns a non-standard resource URL scheme.
Related errors
- ReaperPlugin can only be applied to the root project of a bu
- Reaper process failed. Check log at {} for details
- Unable to create reaper JAR output directory {}
- Reaper process died unexpectedly! Check the log at {}
- /version.properties resource missing
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/3f361f8c5ff932ee.
Report an issue: GitHub.