HMCL-dev/HMCL · error · JsonParseException

pack cannot be null

Error message

pack cannot be null

What it means

PackMcMeta.validate() enforces the model's contract that the `pack` field is present. If the parsed JSON lacked a `pack` object (or it failed its custom deserializer), validation throws JsonParseException with this message.

Solutions

  1. Add a valid `pack` object to pack.mcmeta
  2. Check key spelling and nesting (`{"pack": {"pack_format": N, "description": "..."}}`)
  3. Verify pack_format/supported_formats values are accepted by the deserializer

Example fix

// before
{ "pack_format": 15, "description": "oops" }
// after
{ "pack": { "pack_format": 15, "description": "My pack" } }
Defensive patterns

Strategy: try-catch

Validate before calling

JsonObject root = JsonParser.parseString(Files.readString(path)).getAsJsonObject();
if (!root.has("pack")) throw new IllegalStateException("missing 'pack' section");

Try / catch

try {
    PackMcMeta.fromNonNullJsonFile(path).validate();
} catch (JsonParseException e) {
    log.warn("pack.mcmeta failed validation: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling packMcMeta.validate() after parsing a pack.mcmeta with no `pack` key, or after constructing PackMcMeta without pack.

Common situations: Resource packs missing the required `pack` section; typos like `Pack` or `pack_format` at the wrong nesting level; new-format pack.mcmeta rejected by the PackInfoDeserializer.

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/41f8c342337af2ac. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/addon/meta/PackMcMeta.java:64

        PackMcMeta parsed = LENIENT_GSON.fromJson(jsonString, PackMcMeta.class);
        if (parsed == null)
            throw new JsonParseException("Json object cannot be null.");
        return parsed;
    }

    public static PackMcMeta fromNonNullJsonFile(Path jsonFile) throws JsonParseException, IOException {
        try (var reader = Files.newBufferedReader(jsonFile)) {
            PackMcMeta parsed = LENIENT_GSON.fromJson(reader, PackMcMeta.class);
            if (parsed == null)
                throw new JsonParseException("Json object cannot be null.");
            return parsed;
        }
    }

    @Override
    public void validate() throws JsonParseException {
        if (pack == null)
            throw new JsonParseException("pack cannot be null");
    }

    @JsonAdapter(PackInfoDeserializer.class)
    public record PackInfo(@SerializedName("pack_format") int packFormat,
                           @SerializedName("supported_formats") SupportedFormats supportedFormats,
                           @SerializedName("min_format") PackVersion minPackVersion,
                           @SerializedName("max_format") PackVersion maxPackVersion,
                           @SerializedName("description") LocalAddonFile.Description description) {
        public PackVersion getEffectiveMinVersion() {
            return !minPackVersion.isUnspecified() ? minPackVersion : new PackVersion(packFormat, 0);
        }

        public PackVersion getEffectiveMaxVersion() {
            return !maxPackVersion.isUnspecified() ? maxPackVersion : new PackVersion(packFormat, 0);
        }
    }

    public record SupportedFormats(int min, int max) {

View on GitHub (pinned to 24702dc5a0)