HMCL-dev/HMCL · error · UnsupportedPlatformException

Candidates

Error message

Candidates: ${candidates}

What it means

After locating the per-OS list of Java runtime candidates, MojangJavaDownloadTask scans them for one whose version satisfies the requested major version. If every candidate's parsed version is lower than javaVersion.majorVersion(), it throws UnsupportedPlatformException listing all candidates as JSON, meaning Mojang's index has no runtime new enough for this platform.

Solutions

  1. Switch to a non-Mojang Java download provider (e.g. Adoptium) which distributes current JDKs.
  2. Let the game use the highest runtime available by lowering the requested Java major version requirement.
  3. Refresh the runtime list/clear cache so the latest Mojang index (with newer candidates) is fetched.
  4. Install the required Java manually and point HMCL at it instead of auto-downloading.

Example fix

// before
JavaVersion JAVA_21 = JavaVersion.major(21) with mojang provider;
// after (fallback)
DownloadProvider p = new AdoptiumDownloadProvider(); // or install Java 21 manually and add it in Java settings
Defensive patterns

Strategy: fallback

Validate before calling

// Check any candidate meets the major version before downloading
boolean any = osDownloads.get(component).stream()
    .anyMatch(c -> JavaInfo.parseVersion(c.version().name()) >= javaVersion.majorVersion());

Type guard

if (candidates == null || candidates.isEmpty()) return fallbackProvider();

Try / catch

try { return mojangTask.run().get(); }
catch (UnsupportedPlatformException e) { LOG.warning("No Mojang runtime: " + e.getMessage()); return adoptiumTask.run().get(); }

Prevention

When it happens

Trigger: Requesting a Java major version (e.g. Java 21) whose component exists for the platform in Mojang's index but whose published runtime versions are all below the requested majorVersion, so the loop over `candidates` completes without a match.

Common situations: Launching a game requiring Java 21 while Mojang's index for your OS only lists older runtimes (index lag after a new MC release); asking for an exact newer major than Mojang distributes; a stale/cached copy of the runtime index.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/f9a38de515b76871. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDownloadTask.java:76

    public MojangJavaDownloadTask(DownloadProvider downloadProvider, Path target, Path tempDir, GameJavaVersion javaVersion, String platform) {
        this.target = target;
        this.tempDir = tempDir;
        this.downloadProvider = downloadProvider;
        this.javaDownloadsTask = new GetTask(downloadProvider.injectURLWithCandidates(JAVA_LIST_URL))
                .thenComposeAsync(javaDownloadsJson -> {
                    MojangJavaDownloads allDownloads = JsonUtils.fromNonNullJson(javaDownloadsJson, MojangJavaDownloads.class);

                    Map<String, List<MojangJavaDownloads.JavaDownload>> osDownloads = allDownloads.downloads().get(platform);
                    if (osDownloads == null || !osDownloads.containsKey(javaVersion.component()))
                        throw new UnsupportedPlatformException("Unsupported platform: " + platform);
                    List<MojangJavaDownloads.JavaDownload> candidates = osDownloads.get(javaVersion.component());
                    for (MojangJavaDownloads.JavaDownload download : candidates) {
                        if (JavaInfo.parseVersion(download.version().name()) >= javaVersion.majorVersion()) {
                            this.download = download;
                            return new GetTask(downloadProvider.injectURLWithCandidates(download.manifest().getUrl()));
                        }
                    }
                    throw new UnsupportedPlatformException("Candidates: " + JsonUtils.GSON.toJson(candidates));
                })
                .thenApplyAsync(javaDownloadJson -> JsonUtils.fromNonNullJson(javaDownloadJson, MojangJavaRemoteFiles.class));
    }

    @Override
    public Collection<Task<?>> getDependents() {
        return Collections.singleton(javaDownloadsTask);
    }

    @Override
    public void execute() throws Exception {
        for (Map.Entry<String, MojangJavaRemoteFiles.Remote> entry : javaDownloadsTask.getResult().files().entrySet()) {
            Path dest = tempDir.resolve(entry.getKey());
            if (entry.getValue() instanceof MojangJavaRemoteFiles.RemoteFile file) {
                // Use local file if it already exists
                try {
                    BasicFileAttributes localFileAttributes = Files.readAttributes(dest, BasicFileAttributes.class);
                    if (localFileAttributes.isRegularFile() && file.getDownloads().containsKey("raw")) {

View on GitHub (pinned to 24702dc5a0)