{"record":{"id":"37ee7886e8b6eb9f","repo":"HMCL-dev/HMCL","slug":"theme-pack-must-declare-at-least-one-theme","errorCode":null,"errorMessage":"Theme pack must declare at least one theme","messagePattern":"Theme pack must declare at least one theme","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java","lineNumber":93,"sourceCode":"    /// @param name        the localized display name\n    /// @param authors     the package authors\n    /// @param icon        the optional theme-pack relative icon path\n    /// @param description the optional localized package description\n    /// @param themes      selectable themes declared by the package\n    public ThemePackManifest {\n        id = requirePackageId(id);\n        version = requireNonBlank(version, \"version\");\n        name = requireLocalizedText(name, \"name\");\n        authors = List.copyOf(authors);\n        if (icon != null) {\n            icon = ThemePackAsset.normalizeEntryName(icon);\n        }\n        if (description != null) {\n            description = requireLocalizedText(description, \"description\");\n        }\n        themes = List.copyOf(themes);\n        if (themes.isEmpty()) {\n            throw new IllegalArgumentException(\"Theme pack must declare at least one theme\");\n        }\n        checkThemeIdentities(themes);\n    }\n\n    public boolean isSimpleThemePack() {\n        if (themes.size() == 1) {\n            Theme theme = themes.get(0);\n            return theme.id() == null && theme.name() == null;\n        } else {\n            return false;\n        }\n    }\n\n    /// Returns the package display name in the current locale.\n    ///\n    /// @return the localized display name, or the package ID when no localized text matches\n    public String displayName() {\n        return Objects.requireNonNullElse(name.getText(I18n.getLocale().getCandidateLocales()), id);","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java#L75-L111","documentation":"Thrown in the ThemePackManifest constructor when the parsed themes list is empty. A theme pack must ship at least one theme; an empty list cannot produce a usable pack, so construction fails with IllegalArgumentException after copying the list.","triggerScenarios":"Constructing ThemePackManifest with an empty themes list — typically after reading a manifest whose \"themes\" array is [] or whose only theme failed to contribute entries.","commonSituations":"Hand-edited manifests where all theme entries were deleted; programmatically generated manifests where the theme collection was empty; manifests using \"theme\" erroneously serialized as an empty \"themes\": [] array.","solutions":["Add at least one complete theme object to the themes array.","If a single theme is intended, use the \"theme\" key with one theme object instead of an empty themes array.","Check the code path building the list — ensure theme objects are actually added before constructing ThemePackManifest."],"exampleFix":"// before\n{ \"themes\": [] }\n// after\n{ \"themes\": [ { \"id\": \"main\", \"backgroundColor\": \"#202224\" } ] }","handlingStrategy":"validation","validationCode":"JsonObject manifest = Json.parse(text).asObject();\nJsonArray themes = manifest.getArray(\"themes\", Json.array());\nif (themes.size() == 0 && manifest.get(\"theme\") == null) {\n    throw new IllegalArgumentException(\"manifest must declare at least one theme\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ThemePackManifest m = new ThemePackManifest(...);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"at least one theme\")) {\n        // reject manifest: empty themes array\n    }\n}","preventionTips":["Never ship a manifest with an empty themes array.","Generate manifests programmatically with an assertion that at least one theme was added."],"tags":["theme-pack","manifest","validation","empty-collection"],"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-15T23:17:13.987Z"}