HMCL-dev/HMCL · error · IllegalArgumentException
Theme ID is required when a theme pack declares multiple…
Error message
Theme ID 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 an "id". With more than one theme, IDs are mandatory so users and the launcher can disambiguate and persist the selected theme.
Solutions
- Add a unique "id" (matching the package ID format, e.g. "com.example.dark") to every theme in the array.
- If the pack really has one unnamed theme, use the singular "theme" form or keep the array at exactly one element.
- Validate programmatically: parse the manifest and check each theme's id() before distribution.
Example fix
// before
"themes": [
{ "name": "Dark" },
{ "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("id") || theme.get("id").getAsString().isBlank()) {
throw new IllegalArgumentException("multi-theme packs require an id per theme");
}
}
} Type guard
static boolean multiThemesAllHaveIds(List<Theme> themes) {
return themes.size() <= 1 || themes.stream().allMatch(t -> t.id() != null);
} Try / catch
try {
ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);
} catch (IllegalArgumentException e) {
// report 'theme missing id' with the pack name to the user
} Prevention
- Give every theme an id as soon as you duplicate a theme entry
- Remember ids must match the package ID pattern (letters/digits/dots/dashes)
- Use the singular "theme" form when the pack has exactly one unnamed theme
When it happens
Trigger: Constructing ThemePackManifest (or deserializing its JSON) where themes.size() > 1 and any theme has a null id() — e.g. "themes": [ { "name": "A" }, { "name": "B" } ] without "id" fields.
Common situations: Author converted a single-theme pack (which allows id-less themes) to multi-theme by duplicating the theme entry but forgetting to add unique IDs; a template copied the single-theme example into a multi-theme array.
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
- Theme pack value is missing
- Theme name is required when a theme pack declares multiple…
- Theme-pack author must be an object or a string
- Missing author name:
- Theme packs cannot reference built-in wallpaper
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/ea6f447488e89c0a.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java:182
ArrayList<Theme> themes = new ArrayList<>(array.size());
for (JsonElement item : array) {
if (!(item instanceof JsonObject themeObject)) {
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);
}View on GitHub (pinned to 24702dc5a0)