{"record":{"id":"c8a917b1fcb2024d","repo":"HMCL-dev/HMCL","slug":"expected-jsonobject-but-got","errorCode":null,"errorMessage":"Expected JsonObject but got ","messagePattern":"Expected JsonObject but got ","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameInstanceManifest.java","lineNumber":978,"sourceCode":"                    rawJson\n            );\n        }\n    }\n\n    static final class Adapter extends TypeAdapter<@Nullable GameInstanceManifest> {\n\n        @Override\n        public @Nullable GameInstanceManifest read(JsonReader in) {\n            JsonElement jsonElement = JsonParser.parseReader(in);\n            if (jsonElement.isJsonNull()) {\n                return null;\n            }\n\n            if (jsonElement instanceof JsonObject jsonObject) {\n                return GameInstanceManifest.fromJson(jsonObject, false);\n            }\n\n            throw new JsonParseException(\"Expected JsonObject but got \" + jsonElement.getClass().getName());\n        }\n\n        @Override\n        public void write(JsonWriter out, @Nullable GameInstanceManifest value) throws IOException {\n            if (value != null)\n                JsonUtils.GSON.toJson(value.toJsonObject(), out);\n            else\n                out.nullValue();\n        }\n    }\n}\n","sourceCodeStart":960,"sourceCodeEnd":990,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/GameInstanceManifest.java#L960-L990","documentation":"GameInstanceManifest's Gson JsonDeserializer expects the incoming JsonElement to be a JsonObject; when it is not, it throws JsonParseException('Expected JsonObject but got ' + element class name), naming the actual class (e.g. JsonPrimitive, JsonArray). This surfaces type mismatches between the configured JSON and the expected manifest object shape.","triggerScenarios":"Gson deserializing a manifest where the JSON node is an array, string, number, or JsonNull instead of an object — e.g. a manifest file whose root is [ ... ] or a field deserialized with this adapter holding the wrong JSON type.","commonSituations":"Manifest file saved as a JSON array of instances instead of one object; wrong field wired to a TypeAdapter expecting a manifest; API/remote returning a JSON string that was double-encoded; JsonNull from a missing optional field passed to the adapter.","solutions":["Ensure the JSON being deserialized is a single object at the root (unwrap arrays before parsing)","Parse the element yourself, check jsonElement.isJsonObject(), and give a clearer error or skip it","Fix the producer so it emits an object, not a quoted string or array","Register the TypeAdapter only for fields that truly hold manifest objects"],"exampleFix":"// before\nGameInstanceManifest m = GSON.fromJson(element, GameInstanceManifest.class);\n// after\nif (element.isJsonObject()) {\n    GameInstanceManifest m = GSON.fromJson(element, GameInstanceManifest.class);\n} else {\n    throw new JsonParseException(\"Manifest must be an object, got: \" + element);\n}","handlingStrategy":"type-guard","validationCode":"if (element == null || !element.isJsonObject()) throw new JsonParseException(\"Expected JsonObject, got: \" + (element == null ? \"null\" : element.getClass().getSimpleName()));","typeGuard":"static boolean isManifestObject(JsonElement e) {\n    return e != null && e.isJsonObject();\n}","tryCatchPattern":"try { m = GSON.fromJson(element, GameInstanceManifest.class); }\ncatch (JsonParseException e) { if (e.getMessage().startsWith(\"Expected JsonObject but got\")) { LOG.warning(e.getMessage()); m = null; } else throw e; }","preventionTips":["Check isJsonObject() before handing JsonElements to manifest deserialization","Ensure producers emit objects, not arrays or double-encoded strings","Register the manifest TypeAdapter only where manifest objects are expected"],"tags":["json","gson","type-mismatch"],"backgroundTag":"unexpected-response-shape","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"}