HMCL-dev/HMCL · error · JsonParseException

e

Error message

e

What it means

The JavaManifest deserializer wraps any unexpected Throwable during field parsing (e.g. NullPointerException from missing JSON primitives, ClassCastException, NumberFormatException) into a JsonParseException with cause e. This converts arbitrary failures while reading os.name/os.arch/java.version/update/files into a uniform parse error so Gson callers see one exception type.

Solutions

  1. Unwrap and inspect getCause() on the JsonParseException to see the real failure
  2. Check the manifest JSON for missing/null required keys (os.name, os.arch, java.version) — a missing key yields NPE at getAsString
  3. Validate that "files" entries conform to JavaLocalFiles.Local before deserializing
  4. If a schema change is the cause, update the adapter to use Optional/ofNullable lookups instead of direct getAsJsonPrimitive calls

Example fix

// before
String javaVersion = jsonObject.getAsJsonPrimitive("java.version").getAsString(); // NPE if absent
// after
JsonElement v = jsonObject.get("java.version");
if (v == null || !v.isJsonPrimitive()) throw new JsonParseException("missing java.version");
String javaVersion = v.getAsString();
Defensive patterns

Strategy: try-catch

Validate before calling

JsonObject o = JsonParser.parseString(body).getAsJsonObject();
JsonElement v = o.get("java.version");
if (v == null || !v.isJsonPrimitive()) throw new IOException("Manifest missing java.version primitive");

Type guard

static String requireString(JsonObject o, String key) {
    JsonElement e = o.get(key);
    return e != null && e.isJsonPrimitive() ? e.getAsString() : null;
}

Try / catch

try {
    JavaManifest m = gson.fromJson(body, JavaManifest.class);
} catch (JsonParseException e) {
    Throwable cause = e.getCause();
    LOGGER.log(WARNING, "Manifest parse failed", cause != null ? cause : e);
    // inspect cause to find the real failure (NPE, ClassCast, ...)
}

Prevention

When it happens

Trigger: Any non-JsonParseException Throwable thrown inside the try block — most commonly jsonObject.getAsJsonPrimitive("os.name").getAsString() throwing NPE when the key is absent or not a primitive, or context.deserialize failing on malformed "update"/"files" sections.

Common situations: Manifest with null or non-primitive values for required keys; manifest referencing a nested file entry that fails Local deserialization; upstream schema drift causing silent NPEs.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManifest.java:82

            try {
                JsonObject jsonObject = json.getAsJsonObject();
                OperatingSystem osName = OperatingSystem.parseOSName(jsonObject.getAsJsonPrimitive("os.name").getAsString());
                Architecture osArch = Architecture.parseArchName(jsonObject.getAsJsonPrimitive("os.arch").getAsString());
                String javaVersion = jsonObject.getAsJsonPrimitive("java.version").getAsString();
                String javaVendor = Optional.ofNullable(jsonObject.get("java.vendor")).map(JsonElement::getAsString).orElse(null);

                Map<String, Object> update = jsonObject.has("update") ? context.deserialize(jsonObject.get("update"), Map.class) : null;
                Map<String, JavaLocalFiles.Local> files = jsonObject.has("files") ? context.deserialize(jsonObject.get("files"), LOCAL_FILES_TYPE) : null;

                if (osName == null || osArch == null || javaVersion == null)
                    throw new JsonParseException(json.toString());

                return new JavaManifest(new JavaInfo(Platform.getPlatform(osName, osArch), javaVersion, javaVendor), update, files);
            } catch (JsonParseException e) {
                throw e;
            } catch (Throwable e) {
                throw new JsonParseException(e);
            }
        }
    }
}

View on GitHub (pinned to 24702dc5a0)