{"record":{"id":"91ba12e94a58566b","repo":"HMCL-dev/HMCL","slug":"invalid-theme-pack-manifest","errorCode":null,"errorMessage":"Invalid theme-pack manifest","messagePattern":"Invalid theme-pack manifest","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java","lineNumber":398,"sourceCode":"                    throw new JsonParseException(\"Manifest is null\");\n                }\n                return new LoadedThemePack(normalizedFile, manifest);\n            }\n\n            try (var reader = new ZipArchiveReader(normalizedFile)) {\n                var manifestEntry = reader.getEntry(ThemePackExporter.MANIFEST_ENTRY);\n                if (manifestEntry == null || manifestEntry.isDirectory()) {\n                    throw new IOException(\"Theme pack does not contain \" + ThemePackExporter.MANIFEST_ENTRY);\n                }\n\n                ThemePackManifest manifest;\n                try (var inputStream = reader.getInputStream(manifestEntry)) {\n                    manifest = JsonUtils.fromNonNullJsonFully(inputStream, ThemePackManifest.class);\n                }\n                return new LoadedThemePack(normalizedFile, manifest);\n            }\n        } catch (JsonParseException | IllegalArgumentException e) {\n            throw new IOException(\"Invalid theme-pack manifest\", e);\n        }\n    }\n\n    /// Loads built-in theme pack manifests from launcher resources.\n    private static @Unmodifiable List<InstalledThemePack> loadBuiltinThemePacks() {\n        ArrayList<InstalledThemePack> themePacks = new ArrayList<>();\n        for (String id : BUILTIN_THEME_PACK_IDS) {\n            try {\n                ThemePackManifest manifest;\n\n                try (InputStream input = ThemePackManager.class.getResourceAsStream(\n                        \"/assets/themes/\" + id + \"/\" + ThemePackExporter.MANIFEST_ENTRY)) {\n                    if (input == null) {\n                        throw new IOException(\"Missing built-in theme-pack manifest: \" + id);\n                    }\n\n                    manifest = JsonUtils.fromNonNullJsonFully(input, ThemePackManifest.class);\n                }","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java#L380-L416","documentation":"ThemePackManager.load() throws this IOException when the theme-pack manifest (MANIFEST_ENTRY inside the pack file or directory) fails to parse: JsonUtils.fromNonNullJsonFully/fromJsonFile raises JsonParseException, or LoadedThemePack's compact constructor raises IllegalArgumentException. The original exception is chained as the cause. It signals a corrupt, malformed, or incomplete theme pack rather than an I/O failure.","triggerScenarios":"Calling ThemePackManager.load(Path) (or loadInstalled/install, which delegate to it) on a pack whose theme-pack manifest JSON is syntactically invalid, missing required fields, violates ThemePackManifest record constraints, or whose manifest stream deserializes to null.","commonSituations":"Hand-edited manifest.json with a JSON typo; a pack exported by a newer HMCL version with an incompatible schema; a truncated or partially downloaded .zip; a renamed/mangled file given a .zip extension; a zip whose manifest entry is not UTF-8 JSON.","solutions":["Open the cause (e.getCause()) to see the exact JsonParseException/IllegalArgumentException message and fix the manifest JSON accordingly.","Re-export or re-download the theme pack from a trusted source to replace the corrupt file.","Validate the manifest JSON manually (e.g. with a JSON linter) against ThemePackManifest's required fields before distributing the pack.","If the pack was produced by a different HMCL version, regenerate it with ThemePackExporter using a compatible schema."],"exampleFix":"// before: blindly loading an untrusted pack\nLoadedThemePack pack = ThemePackManager.load(file);\n// after: verify the manifest parses before use\ntry {\n    LoadedThemePack pack = ThemePackManager.load(file);\n} catch (IOException e) {\n    log.warning(\"Discarding corrupt theme pack \" + file + \": \" + e.getCause());\n}","handlingStrategy":"try-catch","validationCode":"// before load\nif (Files.isRegularFile(file) && !Files.isExecutable(file)) throw new IllegalStateException(\"not readable\");\ntry (var zis = new java.util.zip.ZipFile(file.toFile())) {\n    if (zis.getEntry(\"theme-pack.json\") == null) throw new IllegalStateException(\"pack missing manifest entry\");\n}\n// for a directory pack:\nif (Files.isDirectory(file) && !Files.isRegularFile(file.resolve(\"theme-pack.json\")))\n    throw new IllegalStateException(\"pack directory missing theme-pack.json\");","typeGuard":"static boolean looksLikeThemePack(Path p) throws IOException {\n    if (Files.isDirectory(p)) return Files.isRegularFile(p.resolve(\"theme-pack.json\"));\n    if (!Files.isRegularFile(p)) return false;\n    try (var zis = new java.util.zip.ZipFile(p.toFile())) {\n        return zis.getEntry(\"theme-pack.json\") != null;\n    }\n}","tryCatchPattern":"try {\n    LoadedThemePack pack = ThemePackManager.load(file);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Invalid theme-pack manifest\")) {\n    logger.warn(\"Corrupt theme pack \" + file + \": \" + e.getCause());\n    }\n}","preventionTips":["Never hand-edit manifest JSON; use ThemePackExporter to produce packs","Validate manifest JSON against ThemePackManifest fields before distributing","Verify downloaded zips with a checksum to catch truncation","Open e.getCause() to get the precise parse failure when diagnosing"],"tags":["theme-pack","json","io","manifest"],"backgroundTag":"schema-validation-failed","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"}