HMCL-dev/HMCL · error · IOException

Fabric metadata is invalid

Error message

Fabric metadata is invalid

What it means

Thrown by FabricInstallTask.execute when Gson parses the Fabric launcher metadata but yields null, meaning the downloaded JSON is empty, malformed, or not deserializable into FabricInfo. The install cannot proceed without valid loader metadata.

Solutions

  1. Check network connectivity / retry the download of Fabric metadata
  2. Verify the Fabric meta URL and requested loader/game version are valid
  3. Inspect the raw getResult() payload to see what was actually downloaded

Example fix

// before
FabricInfo fabricInfo = JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class);
if (fabricInfo == null) throw new IOException("Fabric metadata is invalid");
// after
String raw = launchMetaTask.getResult();
if (raw == null || raw.isBlank() || !raw.trim().startsWith("{"))
    throw new IOException("Fabric metadata download failed, got: " + preview(raw));
Defensive patterns

Strategy: try-catch

Validate before calling

String raw = launchMetaTask.getResult();
if (raw == null || raw.isBlank() || !raw.stripLeading().startsWith("{"))
    throw new IOException("Fabric metadata is not valid JSON: " + (raw == null ? "null" : raw.substring(0, Math.min(120, raw.length()))));

Type guard

static boolean looksLikeJson(String s) {
    return s != null && !s.isBlank() && (s.stripLeading().startsWith("{") || s.stripLeading().startsWith("["));
}

Try / catch

try {
    installTask.execute();
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().contains("Fabric metadata")) {
        ui.showError("Could not read Fabric metadata; check network/mirror and retry");
    }
}

Prevention

When it happens

Trigger: launchMetaTask.getResult() returns an empty string, invalid JSON, or JSON whose shape Gson cannot map to FabricInfo (GSON.fromJson returns null on empty input).

Common situations: Fabric meta API outage or HTML error page returned instead of JSON, wrong metadata URL, proxy/captive portal interference, or unsupported Fabric version endpoint.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricInstallTask.java:92

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

    @Override
    public Collection<Task<?>> getDependencies() {
        return dependencies;
    }

    @Override
    public boolean isRelyingOnDependencies() {
        return false;
    }

    @Override
    public void execute() throws IOException {
        FabricInfo fabricInfo = JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class);
        if (fabricInfo == null)
            throw new IOException("Fabric metadata is invalid");

        setResult(getPatch(fabricInfo, remote.getGameVersion(), remote.getSelfVersion()));

        dependencies.add(new GameLibrariesTask(dependencyManager, manifest, true, getResult().getLibraries()));
    }

    private GameInstancePatch getPatch(FabricInfo fabricInfo, String gameVersion, String loaderVersion) {
        JsonObject launcherMeta = fabricInfo.launcherMeta;
        Arguments arguments = new Arguments();

        String mainClass;
        if (!launcherMeta.get("mainClass").isJsonObject()) {
            mainClass = launcherMeta.get("mainClass").getAsString();
        } else {
            mainClass = launcherMeta.get("mainClass").getAsJsonObject().get("client").getAsString();
        }

        if (launcherMeta.has("launchwrapper")) {

View on GitHub (pinned to 24702dc5a0)