HMCL-dev/HMCL · error · IOException

Malformed modpack configuration

Error message

Malformed modpack configuration

What it means

McbbsModpackCompletionTask.getFuture() throws IOException("Malformed modpack configuration") when the local modpack configuration file cannot be read or parsed as a ModpackConfiguration<McbbsModpackManifest>. The original cause is swallowed, so the message alone indicates a corrupt/unreadable config.

Solutions

  1. Reinstall the modpack to regenerate a valid configuration file
  2. Inspect the configuration file for corruption/edits and fix or delete it (fresh install will recreate it)
  3. Check disk/permissions so the file can be read
Defensive patterns

Strategy: try-catch

Validate before calling

try { JsonUtils.fromNonNullJson(Files.readString(configurationFile), ModpackConfiguration.typeOf(McbbsModpackManifest.class)); } catch (Exception e) { /* config corrupt - reinstall */ }

Try / catch

try { task.getFuture().get(); } catch (ExecutionException e) { if (e.getCause() instanceof IOException && "Malformed modpack configuration".equals(e.getCause().getMessage())) { /* prompt reinstall */ } }

Prevention

When it happens

Trigger: configuration is null and reading configurationFile throws IOException, or JsonUtils.fromNonNullJson fails with JsonParseException while parsing the stored Mcbbs modpack configuration.

Common situations: Modpack update/resume after the config file was truncated, edited, or written by a different HMCL/modpack version; disk read errors; encoding issues.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/modpack/mcbbs/McbbsModpackCompletionTask.java:109

        dependencyManager.validateGameInstance(instance);
        this.dependency = dependencyManager;
        this.instance = instance;
        this.modManager = instance.getModManager();
        this.configurationFile = instance.getModpackConfigurationFile();
        this.configuration = configuration;

        setStage("hmcl.modpack.download");
    }

    @Override
    public CompletableFuture<Void> getFuture(TaskCompletableFuture executor) {
        return breakable(CompletableFuture.runAsync(wrap(() -> {
            if (configuration == null) {
                // Load configuration from disk
                try {
                    configuration = JsonUtils.fromNonNullJson(Files.readString(configurationFile), ModpackConfiguration.typeOf(McbbsModpackManifest.class));
                } catch (IOException | JsonParseException e) {
                    throw new IOException("Malformed modpack configuration");
                }
            }
            manifest = configuration.getManifest();
            if (manifest == null) throw new CustomException();
        })).thenComposeAsync(unused -> {
            // we first download latest manifest
            return breakable(CompletableFuture.runAsync(wrap(() -> {
                if (StringUtils.isBlank(manifest.getFileApi())) {
                    // skip this phase
                    throw new CustomException();
                }
            })).thenComposeAsync(wrap(unused1 -> {
                return executor.one(new GetTask(manifest.getFileApi() + "/manifest.json"));
            })).thenComposeAsync(wrap(remoteManifestJson -> {
                McbbsModpackManifest remoteManifest;
                // We needs to update modpack from online server.
                try {
                    remoteManifest = JsonUtils.fromNonNullJson(remoteManifestJson, McbbsModpackManifest.class);

View on GitHub (pinned to 24702dc5a0)