HMCL-dev/HMCL · error · IOException
Failed to get Java version from
Error message
Failed to get Java version from
What it means
JavaInfoUtils.fromExecutable successfully ran the org.glavo.info.Main helper but its JSON output did not include a java.version property, so the parsed Result record's javaVersion field is null. This IOException distinguishes 'executable responded but reported no version' from a total probe failure. HMCL requires a version string to classify and use a Java installation, so the runtime is treated as unusable.
Solutions
- Run `<executable> -XshowSettings:properties -version` and confirm `java.version` is set in that runtime.
- Use a standard, complete JDK/JRE build (Temurin, Zulu, Oracle, etc.) instead of the stripped/exotic runtime.
- Run the helper manually (`<exe> -classpath <hmcl.jar> org.glavo.info.Main`) and inspect the emitted JSON for a missing java.version key.
- Update the runtime to a newer release of the same distribution if the property is suppressed.
- Catch this IOException and fall back to another discovered Java installation.
Example fix
// before
JavaInfo info = JavaInfoUtils.fromExecutable(customMinimalJrePath);
// after
try {
JavaInfo info = JavaInfoUtils.fromExecutable(customMinimalJrePath);
} catch (IOException e) {
// runtime did not report java.version; pick a known-good JDK instead
JavaInfo info = JavaInfoUtils.fromExecutable(Path.of("/usr/lib/jvm/temurin-17/bin/java"));
} Defensive patterns
Strategy: try-catch
Validate before calling
Process p = new ProcessBuilder(exe.toString(), "-XshowSettings:properties", "-version").redirectErrorStream(true).start();
String out = new String(p.getInputStream().readAllBytes());
if (!out.contains("java.version")) LOG.warning("runtime reports no java.version: " + exe); Try / catch
try {
return JavaInfoUtils.fromExecutable(exe);
} catch (IOException e) {
if (e.getMessage().startsWith("Failed to get Java version")) {
LOG.warning("Runtime lacks java.version, skipping: " + exe);
}
return null; // or fall back to another runtime
} Prevention
- Prefer complete, standard JDK distributions over minimal or custom-built JREs.
- Test-probe each runtime once and cache results; exclude runtimes that fail.
- Inspect `-XshowSettings:properties` output for exotic runtimes before trusting them.
- Keep runtimes up to date; old/exotic builds may suppress system properties.
- Never hand-patch system properties in custom JRE builds used with HMCL.
When it happens
Trigger: Calling JavaInfoUtils.fromExecutable(Path) on a runtime whose helper output JSON lacks `java.version` (Gson leaves the record field null).
Common situations: Minimal/exotic JRE builds (e.g. custom, embedded, or very old runtimes) that omit or mask the java.version system property; a wrapper script that mangles the helper's JSON output; a JRE built with patched system properties.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Failed to get Java info from
- name existing
- Texture url is empty
- Failed to download texture
- Platform is mismatch: expected
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/c1c1366759d3f11f.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/java/JavaInfoUtils.java:63
Path thisPath = JarUtils.thisJarPath();
if (thisPath == null) {
throw new IOException("Failed to find current HMCL location");
}
try {
Result result = JsonUtils.GSON.fromJson(SystemUtils.run(
executable.toString(),
"-classpath",
thisPath.toString(),
org.glavo.info.Main.class.getName()
), Result.class);
if (result == null) {
throw new IOException("Failed to get Java info from " + executable);
}
if (result.javaVersion == null) {
throw new IOException("Failed to get Java version from " + executable);
}
Architecture architecture = Architecture.parseArchName(result.osArch);
Platform platform = Platform.getPlatform(OperatingSystem.CURRENT_OS,
architecture != Architecture.UNKNOWN
? architecture
: Architecture.SYSTEM_ARCH);
return new JavaInfo(platform, result.javaVersion, result.javaVendor);
} catch (IOException e) {
throw e;
} catch (Throwable e) {
throw new IOException(e);
}
}
@JsonSerializable
private record Result(@SerializedName("os.name") String osName, @SerializedName("os.arch") String osArch,View on GitHub (pinned to 24702dc5a0)