HMCL-dev/HMCL · error · IOException

No download url is available

Error message

No download url is available

What it means

RemoteVersion.fetch queries HMCL's update metadata endpoint and expects a JSON object containing both "jar" (download URL) and "jarsha1" (hash). If either is missing so a JAR-type RemoteVersion cannot be built, it throws IOException("No download url is available"). This protects against update metadata that lacks a downloadable artifact.

Solutions

  1. Retry later — the update server metadata may be temporarily incomplete
  2. Switch to a different update channel in HMCL settings
  3. Download the latest HMCL jar manually from the official site and replace the current one
  4. If operating the update server, populate the "jar" and "jarsha1" fields in the channel metadata

Example fix

// before
if (jarUrl != null && jarHash != null) {
    return new RemoteVersion(...);
} else {
    throw new IOException("No download url is available");
}
// after
if (jarUrl != null && jarHash != null) {
    return new RemoteVersion(...);
} else {
    throw new IOException("No download url is available for channel " + channel
        + " version " + version + " (jar=" + jarUrl + ")");
}
Defensive patterns

Strategy: fallback

Validate before calling

// probe metadata before trusting it
JsonObject meta = JsonParser.parseString(body).getAsJsonObject();
if (!meta.has("jar") || !meta.has("jarsha1")) {
    // channel metadata incomplete: fall back to manual download
}

Try / catch

try {
    RemoteVersion v = RemoteVersion.fetch(channel, version, preview);
} catch (IOException e) {
    if (e.getMessage().equals("No download url is available")) {
        openOfficialDownloadPage(); // manual update path
    } else throw e;
}

Prevention

When it happens

Trigger: Checking for updates when the server's metadata JSON has no "jar" or no "jarsha1" entry (null from Optional.orElse(null)) — the channel responds, but without a usable artifact link.

Common situations: Update server misconfiguration; a channel serving metadata-only entries (e.g. announcing updates distributed another way); partial/cached JSON responses; unofficial or deprecated update channels.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java:44

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Optional;

public record RemoteVersion(UpdateChannel channel, String version, String url, Type type, IntegrityCheck integrityCheck,
                            boolean preview, boolean force) {

    public static RemoteVersion fetch(UpdateChannel channel, boolean preview, String url) throws IOException {
        try {
            JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(url), JsonObject.class);
            String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing"));
            String jarUrl = Optional.ofNullable(response.get("jar")).map(JsonElement::getAsString).orElse(null);
            String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null);
            boolean force = Optional.ofNullable(response.get("force")).map(JsonElement::getAsBoolean).orElse(false);
            if (jarUrl != null && jarHash != null) {
                return new RemoteVersion(channel, version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash), preview, force);
            } else {
                throw new IOException("No download url is available");
            }
        } catch (JsonParseException e) {
            throw new IOException("Malformed response", e);
        }
    }

    @Override
    public @NotNull String toString() {
        return "[" + version + " from " + url + "]";
    }

    public enum Type {
        JAR
    }
}

View on GitHub (pinned to 24702dc5a0)