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
- Unwrap and inspect getCause() on the JsonParseException to see the real failure
- Check the manifest JSON for missing/null required keys (os.name, os.arch, java.version) — a missing key yields NPE at getAsString
- Validate that "files" entries conform to JavaLocalFiles.Local before deserializing
- 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
- Always unwrap getCause() to diagnose the underlying failure
- Use null-safe JSON access (JsonParser-based Optional lookups) in adapters
- Reject manifests early when required keys are missing primitives
- Unit-test the deserializer against malformed manifest fixtures
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
- json.toString()
- json.toString()
- Account private data is not an object
- Game directory ID cannot be null
- Game directory ID cannot be nil
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)