HMCL-dev/HMCL · error · IllegalArgumentException

Theme name is required when a theme pack declares multiple…

Error message

Theme name is required when a theme pack declares multiple themes

What it means

Thrown by checkThemeIdentities (invoked from the ThemePackManifest compact constructor) when a manifest declares multiple themes but at least one of them lacks a "name". Names are required alongside IDs in multi-theme packs so the UI can present a human-readable label for each selectable theme.

Solutions

  1. Add a non-blank "name" (string or localized object) to every theme in the "themes" array.
  2. Ensure every theme has BOTH id and name when the pack declares more than one theme.
  3. Test-load the pack before release to surface this IllegalArgumentException early.

Example fix

// before
"themes": [
  { "id": "dark" },
  { "id": "light", "name": "Light" }
]
// after
"themes": [
  { "id": "dark", "name": "Dark" },
  { "id": "light", "name": "Light" }
]
Defensive patterns

Strategy: validation

Validate before calling

JsonArray themes = manifestJson.getAsJsonArray("themes");
if (themes.size() > 1) {
    for (JsonElement t : themes) {
        JsonObject theme = t.getAsJsonObject();
        if (!theme.has("name")) {
            throw new IllegalArgumentException("multi-theme packs require a name per theme");
        }
    }
}

Type guard

static boolean multiThemesAllHaveNames(List<Theme> themes) {
    return themes.size() <= 1 || themes.stream().allMatch(t -> t.name() != null);
}

Try / catch

try {
    ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);
} catch (IllegalArgumentException e) {
    // report 'theme missing name' with the pack name to the user
}

Prevention

When it happens

Trigger: Constructing ThemePackManifest (or deserializing its JSON) where themes.size() > 1 and any theme has a null name() — e.g. "themes": [ { "id": "dark" }, { "id": "light", "name": "Light" } ].

Common situations: Author added IDs (fixing the ID error) but omitted display names; a generated manifest wrote id-only theme stubs; a localization file was expected to supply names at runtime but the manifest itself never declared them.

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/03910ef2a049b773. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java:185

                throw new JsonParseException("Theme-pack theme must be an object");
            }
            themes.add(Theme.fromJson(themeObject, true));
        }
        return themes;
    }

    /// Checks that theme IDs and names are present whenever the manifest needs them for disambiguation.
    private static void checkThemeIdentities(List<Theme> themes) {
        if (themes.size() <= 1) {
            return;
        }

        for (Theme theme : themes) {
            if (theme.id() == null) {
                throw new IllegalArgumentException("Theme ID is required when a theme pack declares multiple themes");
            }
            if (theme.name() == null) {
                throw new IllegalArgumentException("Theme name is required when a theme pack declares multiple themes");
            }
        }
    }

    /// Reads a required string member.
    private static String requireMemberString(JsonObject object, String fieldName) {
        JsonElement element = object.get(fieldName);
        if (element == null) {
            throw new JsonParseException("Theme-pack manifest is missing " + fieldName);
        }
        if (!(element instanceof JsonPrimitive primitive) || !primitive.isString()) {
            throw new JsonParseException("Theme-pack manifest field must be a string: " + fieldName);
        }
        return requireNonBlank(primitive.getAsString(), fieldName);
    }

    /// Parses a localized text value.
    static LocalizedText parseLocalizedText(JsonElement element, String field) {

View on GitHub (pinned to 24702dc5a0)