{"record":{"id":"9f166714544881be","repo":"HMCL-dev/HMCL","slug":"game-directory-path-cannot-be-null","errorCode":null,"errorMessage":"Game directory path cannot be null","messagePattern":"Game directory path cannot be null","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/setting/GameDirectory.java","lineNumber":199,"sourceCode":"                jsonObject.add(\"legacyGameSettings\", context.serialize(src.getLegacyGameSettings(), GameSettingsPresetID.class));\n            }\n\n            return jsonObject;\n        }\n\n        /// Deserializes a game directory from JSON.\n        @Override\n        public @Nullable GameDirectory deserialize(@Nullable JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n            if (!(json instanceof JsonObject obj)) return null;\n            GameDirectoryID id = context.deserialize(obj.get(\"id\"), GameDirectoryID.class);\n            if (id == null) {\n                throw new JsonParseException(\"Game directory ID cannot be null\");\n            } else if (GameDirectoryID.NIL.equals(id)) {\n                throw new JsonParseException(\"Game directory ID cannot be nil\");\n            }\n            PortablePath path = context.deserialize(obj.get(\"path\"), PortablePath.class);\n            if (path == null) {\n                throw new JsonParseException(\"Game directory path cannot be null\");\n            }\n            @Nullable LocalizedText name = context.deserialize(obj.get(\"name\"), LocalizedText.class);\n\n            return new GameDirectory(id,\n                    name,\n                    path,\n                    context.deserialize(obj.get(\"legacyGameSettings\"), GameSettingsPresetID.class));\n        }\n\n    }\n}\n","sourceCodeStart":181,"sourceCodeEnd":211,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/setting/GameDirectory.java#L181-L211","documentation":"GameDirectory's deserializer requires a non-null \"path\" field. After validating the id, it deserializes obj.get(\"path\") into PortablePath; if absent or unresolvable, it throws JsonParseException(\"Game directory path cannot be null\") since a game directory without a filesystem location is meaningless.","triggerScenarios":"Deserializing a settings JSON game-directory object that has a valid id but no \"path\" member, or a \"path\" value that PortablePath's adapter cannot decode into a non-null PortablePath.","commonSituations":"Hand-edited settings.json where path was removed or misspelled (e.g. \"dir\" instead of \"path\"); entries produced by a different HMCL fork using different keys; truncated settings file cutting off the path field.","solutions":["Add the missing \"path\" field with a valid filesystem path to the entry in settings.json","Check the key spelling/casing — it must be exactly \"path\" and must match PortablePath's expected format","Re-add the game directory via the HMCL UI instead of hand-editing the settings file","Remove the malformed entry and restore settings.json from a backup"],"exampleFix":"// before\n{ \"id\": \"7c9e6679-7425-40de-944b-e07fc1f90ae7\" }\n// after\n{ \"id\": \"7c9e6679-7425-40de-944b-e07fc1f90ae7\", \"path\": \"D:/minecraft\" }","handlingStrategy":"validation","validationCode":"JsonObject entry = ...;\nif (!entry.has(\"path\") || entry.get(\"path\").isJsonNull())\n    throw new IOException(\"Game directory entry missing path\");","typeGuard":"static boolean hasDirectoryPath(JsonObject entry) {\n    JsonElement p = entry.get(\"path\");\n    return p != null && !p.isJsonNull();\n}","tryCatchPattern":"try {\n    GameDirectory d = gson.fromJson(entry, GameDirectory.class);\n} catch (JsonParseException e) {\n    LOGGER.warning(\"Malformed game directory (missing path?): \" + e.getMessage());\n    // drop or repair the entry before loading settings\n}","preventionTips":["Use exact key names (\"id\", \"path\", \"name\") matching the deserializer","Prefer the HMCL UI over manual settings.json edits","Back up settings.json before editing or syncing across machines","Validate entries against the schema when migrating configs between HMCL versions"],"tags":["json","deserialization","settings","config"],"backgroundTag":"missing-required-config-field","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"}