HMCL-dev/HMCL · error · JsonParseException
Theme-pack manifest is missing themes array
Error message
Theme-pack manifest is missing themes array
What it means
Thrown by ThemePackManifest.readThemes when a manifest declares a "themes" member whose value is not a JSON array. The parser requires an array of theme objects when the multi-theme form is used; any other JSON type (object, string, number, boolean, null) is rejected so malformed packs fail fast at load time instead of producing a broken theme list.
Solutions
- Change "themes" to a JSON array: "themes": [ { ... }, { ... } ].
- If the pack has only one theme, use the singular form "theme": { ... } instead.
- Validate the manifest JSON structure (e.g. with a JSON schema or linter) before packaging.
Example fix
// before
"themes": {
"dark": { "name": "Dark" }
}
// after
"themes": [
{ "id": "dark", "name": "Dark" }
] Defensive patterns
Strategy: validation
Validate before calling
JsonElement themes = manifestJson.get("themes");
if (themes != null && !(themes instanceof JsonArray)) {
throw new IllegalArgumentException("'themes' must be a JSON array");
} Type guard
static boolean hasThemesArray(JsonObject manifest) {
return manifest.get("themes") instanceof JsonArray;
} Try / catch
try {
ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);
} catch (JsonParseException e) {
// reject the pack and show a user-facing 'invalid manifest' message
} Prevention
- Use the singular "theme" form only for single-theme packs
- Round-trip your manifest through ThemePackManifest's serializer before release
- Validate manifest JSON against the theme-pack schema in CI
When it happens
Trigger: Deserializing a theme-pack manifest.json that contains "themes": { ... } (an object instead of an array), or "themes": "theme1", or "themes": null. Only reached when the manifest has a "themes" key but its value fails the `element instanceof JsonArray` check.
Common situations: Hand-edited manifest where the author wrapped themes in an object keyed by theme ID; a generator or script that serialized themes as a JSON object map; copy-paste of a single-theme pack and renaming "theme" to "themes" without converting the value to an array.
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
- Theme-pack author must be an object or a string
- Missing author name:
- Manifest is null
- Invalid theme-pack manifest
- Theme packs cannot reference built-in wallpaper
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/68161ed42c18d9e1.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java:158
/// Reads the required theme declaration.
private static List<Theme> readThemes(JsonObject object) {
boolean hasSingleTheme = object.has("theme");
boolean hasMultipleThemes = object.has("themes");
if (hasSingleTheme == hasMultipleThemes) {
throw new JsonParseException("Theme-pack manifest must declare exactly one of theme or themes");
}
if (hasSingleTheme) {
JsonElement element = object.get("theme");
if (!(element instanceof JsonObject themeObject)) {
throw new JsonParseException("Theme-pack theme must be an object");
}
return List.of(Theme.fromJson(themeObject, false));
}
JsonElement element = object.get("themes");
if (!(element instanceof JsonArray array)) {
throw new JsonParseException("Theme-pack manifest is missing themes array");
}
if (array.isEmpty()) {
throw new JsonParseException("Theme-pack themes array must declare at least one theme");
}
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) {View on GitHub (pinned to 24702dc5a0)