HMCL-dev/HMCL · error · JsonParseException

Game directory path cannot be null

Error message

Game directory path cannot be null

What it means

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.

Solutions

  1. Add the missing "path" field with a valid filesystem path to the entry in settings.json
  2. Check the key spelling/casing — it must be exactly "path" and must match PortablePath's expected format
  3. Re-add the game directory via the HMCL UI instead of hand-editing the settings file
  4. Remove the malformed entry and restore settings.json from a backup

Example fix

// before
{ "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7" }
// after
{ "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "path": "D:/minecraft" }
Defensive patterns

Strategy: validation

Validate before calling

JsonObject entry = ...;
if (!entry.has("path") || entry.get("path").isJsonNull())
    throw new IOException("Game directory entry missing path");

Type guard

static boolean hasDirectoryPath(JsonObject entry) {
    JsonElement p = entry.get("path");
    return p != null && !p.isJsonNull();
}

Try / catch

try {
    GameDirectory d = gson.fromJson(entry, GameDirectory.class);
} catch (JsonParseException e) {
    LOGGER.warning("Malformed game directory (missing path?): " + e.getMessage());
    // drop or repair the entry before loading settings
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/setting/GameDirectory.java:199

                jsonObject.add("legacyGameSettings", context.serialize(src.getLegacyGameSettings(), GameSettingsPresetID.class));
            }

            return jsonObject;
        }

        /// Deserializes a game directory from JSON.
        @Override
        public @Nullable GameDirectory deserialize(@Nullable JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            if (!(json instanceof JsonObject obj)) return null;
            GameDirectoryID id = context.deserialize(obj.get("id"), GameDirectoryID.class);
            if (id == null) {
                throw new JsonParseException("Game directory ID cannot be null");
            } else if (GameDirectoryID.NIL.equals(id)) {
                throw new JsonParseException("Game directory ID cannot be nil");
            }
            PortablePath path = context.deserialize(obj.get("path"), PortablePath.class);
            if (path == null) {
                throw new JsonParseException("Game directory path cannot be null");
            }
            @Nullable LocalizedText name = context.deserialize(obj.get("name"), LocalizedText.class);

            return new GameDirectory(id,
                    name,
                    path,
                    context.deserialize(obj.get("legacyGameSettings"), GameSettingsPresetID.class));
        }

    }
}

View on GitHub (pinned to 24702dc5a0)