{"record":{"id":"8a84dafc8689ceff","repo":"HMCL-dev/HMCL","slug":"e","errorCode":null,"errorMessage":"e","messagePattern":"e","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManifest.java","lineNumber":82,"sourceCode":"\n            try {\n                JsonObject jsonObject = json.getAsJsonObject();\n                OperatingSystem osName = OperatingSystem.parseOSName(jsonObject.getAsJsonPrimitive(\"os.name\").getAsString());\n                Architecture osArch = Architecture.parseArchName(jsonObject.getAsJsonPrimitive(\"os.arch\").getAsString());\n                String javaVersion = jsonObject.getAsJsonPrimitive(\"java.version\").getAsString();\n                String javaVendor = Optional.ofNullable(jsonObject.get(\"java.vendor\")).map(JsonElement::getAsString).orElse(null);\n\n                Map<String, Object> update = jsonObject.has(\"update\") ? context.deserialize(jsonObject.get(\"update\"), Map.class) : null;\n                Map<String, JavaLocalFiles.Local> files = jsonObject.has(\"files\") ? context.deserialize(jsonObject.get(\"files\"), LOCAL_FILES_TYPE) : null;\n\n                if (osName == null || osArch == null || javaVersion == null)\n                    throw new JsonParseException(json.toString());\n\n                return new JavaManifest(new JavaInfo(Platform.getPlatform(osName, osArch), javaVersion, javaVendor), update, files);\n            } catch (JsonParseException e) {\n                throw e;\n            } catch (Throwable e) {\n                throw new JsonParseException(e);\n            }\n        }\n    }\n}\n","sourceCodeStart":64,"sourceCodeEnd":87,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManifest.java#L64-L87","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nString javaVersion = jsonObject.getAsJsonPrimitive(\"java.version\").getAsString(); // NPE if absent\n// after\nJsonElement v = jsonObject.get(\"java.version\");\nif (v == null || !v.isJsonPrimitive()) throw new JsonParseException(\"missing java.version\");\nString javaVersion = v.getAsString();","handlingStrategy":"try-catch","validationCode":"JsonObject o = JsonParser.parseString(body).getAsJsonObject();\nJsonElement v = o.get(\"java.version\");\nif (v == null || !v.isJsonPrimitive()) throw new IOException(\"Manifest missing java.version primitive\");","typeGuard":"static String requireString(JsonObject o, String key) {\n    JsonElement e = o.get(key);\n    return e != null && e.isJsonPrimitive() ? e.getAsString() : null;\n}","tryCatchPattern":"try {\n    JavaManifest m = gson.fromJson(body, JavaManifest.class);\n} catch (JsonParseException e) {\n    Throwable cause = e.getCause();\n    LOGGER.log(WARNING, \"Manifest parse failed\", cause != null ? cause : e);\n    // inspect cause to find the real failure (NPE, ClassCast, ...)\n}","preventionTips":["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"],"tags":["json","deserialization","wrapped-exception"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}