{"record":{"id":"b9be9e937792a6d4","repo":"HMCL-dev/HMCL","slug":"theme-pack-asset-is-missing-entryname","errorCode":null,"errorMessage":"Theme-pack asset is missing: ${entryName}","messagePattern":"Theme-pack asset is missing: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackResource.java","lineNumber":122,"sourceCode":"            zipFile = Objects.requireNonNull(zipFile).toAbsolutePath().normalize();\n            entryName = ThemePackAsset.normalizeEntryName(entryName);\n        }\n\n        /// Returns the zip entry name.\n        @Override\n        public String name() {\n            return entryName;\n        }\n\n        /// Opens the zip entry and closes the zip file when the returned stream is closed.\n        @Override\n        public InputStream openStream() throws IOException {\n            ZipArchiveReader zip = new ZipArchiveReader(zipFile, StandardCharsets.UTF_8);\n            boolean success = false;\n            try {\n                ZipArchiveEntry entry = zip.getEntry(entryName);\n                if (entry == null || entry.isDirectory()) {\n                    throw new IOException(\"Theme-pack asset is missing: \" + entryName);\n                }\n                InputStream input = zip.getInputStream(entry);\n                success = true;\n                return new ZipEntryInputStream(input, zip);\n            } finally {\n                if (!success) {\n                    zip.close();\n                }\n            }\n        }\n    }\n\n    /// A resource stored in launcher-bundled classpath resources.\n    ///\n    /// @param resourcePath the classpath resource path\n    /// @param entryName    the theme-pack entry name\n    @NotNullByDefault\n    record Builtin(String resourcePath, String entryName) implements ThemePackResource {","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackResource.java#L104-L140","documentation":"ZipFileThemePackResource.openStream opens the pack's zip and looks up entryName; when the entry is absent or is a directory, it throws IOException \"Theme-pack asset is missing: <entryName>\". This means the theme pack does not physically contain the requested asset.","triggerScenarios":"Requesting a wallpaper/font asset path that is not inside the theme-pack zip; the entry exists but is a directory entry; manifest references an asset that was never packaged or was deleted.","commonSituations":"Manifest edited to reference wallpaper.png but the zip contains images/wallpaper.jpg; repacking the zip without the asset folder; path case mismatch inside the zip.","solutions":["Verify the asset exists in the zip at exactly the path the manifest references (case-sensitive).","Add the missing file to the zip and repack the theme pack.","If the manifest path is wrong (extra directory prefix), correct the manifest entry path."],"exampleFix":"// before\n\"wallpaper\": \"wallpaper.png\"   // file is actually at assets/wallpaper.png\n// after\n\"wallpaper\": \"assets/wallpaper.png\"","handlingStrategy":"try-catch","validationCode":"try (ZipArchiveReader zip = new ZipArchiveReader(zipFile, UTF_8)) { boolean present = zip.getEntry(entryName) != null && !zip.getEntry(entryName).isDirectory(); }","typeGuard":null,"tryCatchPattern":"try (InputStream in = resource.openStream()) { use(in); } catch (IOException e) { useDefaultWallpaper(); }","preventionTips":["Cross-check every asset path in the manifest against zip entries after packaging","Keep asset paths case-exact","Never reference directories as assets"],"tags":["theme-pack","zip","resource-not-found"],"backgroundTag":"resource-not-found","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"}