{"record":{"id":"4e5e2b6b3cd07ab4","repo":"HMCL-dev/HMCL","slug":"theme-pack-themes-array-must-declare-at-least-one","errorCode":null,"errorMessage":"Theme-pack themes array must declare at least one theme","messagePattern":"Theme-pack themes array must declare at least one theme","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java","lineNumber":161,"sourceCode":"        boolean hasMultipleThemes = object.has(\"themes\");\n        if (hasSingleTheme == hasMultipleThemes) {\n            throw new JsonParseException(\"Theme-pack manifest must declare exactly one of theme or themes\");\n        }\n\n        if (hasSingleTheme) {\n            JsonElement element = object.get(\"theme\");\n            if (!(element instanceof JsonObject themeObject)) {\n                throw new JsonParseException(\"Theme-pack theme must be an object\");\n            }\n            return List.of(Theme.fromJson(themeObject, false));\n        }\n\n        JsonElement element = object.get(\"themes\");\n        if (!(element instanceof JsonArray array)) {\n            throw new JsonParseException(\"Theme-pack manifest is missing themes array\");\n        }\n        if (array.isEmpty()) {\n            throw new JsonParseException(\"Theme-pack themes array must declare at least one theme\");\n        }\n\n        ArrayList<Theme> themes = new ArrayList<>(array.size());\n        for (JsonElement item : array) {\n            if (!(item instanceof JsonObject themeObject)) {\n                throw new JsonParseException(\"Theme-pack theme must be an object\");\n            }\n            themes.add(Theme.fromJson(themeObject, true));\n        }\n        return themes;\n    }\n\n    /// Checks that theme IDs and names are present whenever the manifest needs them for disambiguation.\n    private static void checkThemeIdentities(List<Theme> themes) {\n        if (themes.size() <= 1) {\n            return;\n        }\n","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java#L143-L179","documentation":"Thrown by ThemePackManifest.readThemes when the \"themes\" array is present and is an array but contains zero elements. A theme pack must ship at least one selectable theme; an empty array would make the pack unusable, so it is rejected during deserialization.","triggerScenarios":"Deserializing a manifest with \"themes\": []. Any load of a theme pack whose manifest declares the multi-theme form but lists no themes.","commonSituations":"Author removed all theme entries while refactoring the manifest; a build script stripped the array contents; a pack template was distributed without its example theme filled in.","solutions":["Add at least one theme object to the \"themes\" array.","If only one theme is intended, either keep it in the array or switch to the singular \"theme\": { ... } form.","Ship a placeholder theme if the pack must be structurally valid before real themes are authored."],"exampleFix":"// before\n\"themes\": []\n// after\n\"themes\": [\n  { \"id\": \"default\", \"name\": \"Default\" }\n]","handlingStrategy":"validation","validationCode":"JsonArray themes = manifestJson.has(\"themes\") && manifestJson.get(\"themes\") instanceof JsonArray a ? a : null;\nif (themes != null && themes.isEmpty()) {\n    throw new IllegalArgumentException(\"'themes' must contain at least one theme\");\n}","typeGuard":"static boolean hasNonEmptyThemesArray(JsonObject manifest) {\n    return manifest.get(\"themes\") instanceof JsonArray a && !a.isEmpty();\n}","tryCatchPattern":"try {\n    ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);\n} catch (JsonParseException e) {\n    // mark the pack invalid; surface 'no themes declared' to the user\n}","preventionTips":["Never distribute a pack template with an empty themes array","Add a packaging test that loads every shipped manifest","If a pack is theme-less during development, keep one placeholder theme"],"tags":["json","theme-pack","manifest","empty"],"backgroundTag":"empty-required-field","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}