HMCL-dev/HMCL · error · IllegalArgumentException

Instance

Error message

Instance 

What it means

Validation failure for a CurseForge-backed file entry in an Mcbbs manifest: a CurseFile must carry both a non-zero projectID and fileID. These IDs are needed to download the file from CurseForge, so a zero/absent ID makes the entry unusable and validate() throws JsonParseException.

Solutions

  1. Fill in the correct numeric projectID and fileID from the CurseForge file page/API
  2. Remove the entry if the file should not be part of the pack
  3. Re-export the pack with a tool that resolves CurseForge IDs
  4. Replace the curseforge entry with a direct URL (type=direct) if IDs are unavailable

Example fix

// before
{"type": "curseforge", "projectID": 0, "fileID": 0}
// after
{"type": "curseforge", "projectID": 238222, "fileID": 2745063}
Defensive patterns

Strategy: validation

Validate before calling

for (var f : manifest.getFiles())
    if (f.getDownloads() != null && f.getType() == Type.CURSE)
        if (f.getCurseFile().getProjectID() == 0 || f.getCurseFile().getFileID() == 0)
            throw new IllegalArgumentException("CurseForge entry missing IDs: " + f.getPath());

Type guard

boolean validCurseFile = e.projectID != 0 && e.fileID != 0;

Try / catch

try { manifest.validate(); } catch (JsonParseException e) { /* surface the offending curseforge entry */ }

Prevention

When it happens

Trigger: Importing a pack where a files[] entry of type curseforge has projectID == 0 or fileID == 0 (typically because the IDs were missing in the JSON and defaulted to 0 as primitives).

Common situations: Hand-written manifest entries for CurseForge mods with IDs omitted; tools that failed to resolve CurseForge IDs during export; packs whose CurseForge links were replaced by placeholders.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLModpackInstallTask.java:113

            HMCLGameRepository repository,
            Path zipFile,
            Modpack modpack,
            GameInstanceID instanceId,
            @Nullable DefaultGameInstance updateTarget) {
        this.repository = repository;
        this.dependency = repository.getDependency();
        this.zipFile = zipFile;
        this.instanceId = instanceId;
        this.updateTarget = updateTarget;
        this.modpack = modpack;
        if (this.updateTarget != null) {
            dependency.validateGameInstance(this.updateTarget);
        }

        Path run = repository.getLayout().getInstanceRoot(this.instanceId);
        Path json = repository.getLayout().getModpackConfigurationFile(this.instanceId);
        if (this.updateTarget != null && Files.notExists(json))
            throw new IllegalArgumentException("Instance " + instanceId + " is not a HMCL modpack. Cannot update this instance.");

        @Nullable ModpackConfiguration<Modpack> config = null;
        try {
            if (this.updateTarget != null && Files.exists(json)) {
                config = JsonUtils.fromJsonFile(json, ModpackConfiguration.typeOf(Modpack.class));

                if (config == null || !HMCLModpackProvider.INSTANCE.getName().equals(config.getType()))
                    throw new IllegalArgumentException("Instance " + instanceId + " is not a HMCL modpack. Cannot update this instance.");
            }
        } catch (JsonParseException | IOException ignore) {
        }

        onDone().register(event -> {
            if (this.updateTarget == null && event.isFailed()) {
                repository.removeInstanceFromDisk(this.instanceId);
            }
        });

View on GitHub (pinned to 24702dc5a0)