{"record":{"id":"34fcbb6a76506deb","repo":"HMCL-dev/HMCL","slug":"theme-pack-location-has-no-readable-file","errorCode":null,"errorMessage":"Theme pack location has no readable file: ","messagePattern":"Theme pack location has no readable file: ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java","lineNumber":1206,"sourceCode":"                opacity);\n    }\n\n    /// Resolves one asset referenced by an installed theme pack.\n    ///\n    /// @param location the installed theme-pack location\n    /// @param entryName the theme-pack relative asset entry name\n    /// @return the resolved resource\n    /// @throws IOException if the asset cannot be read\n    public static ThemePackResource resolveInstalledAsset(ThemePackLocation location, String entryName) throws IOException {\n        Objects.requireNonNull(location);\n        String normalizedEntryName = ThemePackAsset.normalizeEntryName(entryName);\n        if (location instanceof ThemePackLocation.Builtin builtin) {\n            return resolveBuiltinAsset(builtin, normalizedEntryName);\n        }\n\n        @Nullable Path file = location.file();\n        if (file == null) {\n            throw new IOException(\"Theme pack location has no readable file: \" + location);\n        }\n        Path installedFile = file.toAbsolutePath().normalize();\n        if (Files.isDirectory(installedFile)) {\n            Path assetFile = installedFile.resolve(normalizedEntryName).normalize();\n            if (!assetFile.startsWith(installedFile)) {\n                throw new IOException(\"Theme-pack asset escapes the installed directory: \" + normalizedEntryName);\n            }\n            if (!Files.isRegularFile(assetFile)) {\n                throw new IOException(\"Installed theme-pack asset is missing: \" + normalizedEntryName);\n            }\n            return new ThemePackResource.File(assetFile, normalizedEntryName);\n        }\n        if (!Files.isRegularFile(installedFile)) {\n            throw new IOException(\"Installed theme-pack file is missing: \" + installedFile);\n        }\n\n        try (ZipArchiveReader zipFile = new ZipArchiveReader(installedFile, StandardCharsets.UTF_8)) {\n            ZipArchiveEntry entry = zipFile.getEntry(normalizedEntryName);","sourceCodeStart":1188,"sourceCodeEnd":1224,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java#L1188-L1224","documentation":"resolveInstalledAsset(location, entryName) needs a concrete file backing the theme-pack location. If the ThemePackLocation is not Builtin and its file() returns null, there is no readable source for assets and this IOException is thrown with the location's string form.","triggerScenarios":"Calling ThemePackManager.resolveInstalledAsset() with a non-builtin ThemePackLocation whose file is null — e.g. a location descriptor for a pack that was never installed or whose path was cleared.","commonSituations":"Resolving assets for a pack record persisted to config without its path; constructing ThemePackLocation instances manually with null files; resolving assets after the pack registry lost its mapping.","solutions":["Ensure the location refers to an installed pack directory or zip file (set file() via ThemePackManager.install or a valid ThemePackLocation.File).","Check location.file() != null before resolving assets and surface a user-facing 'install the pack first' message otherwise.","Re-resolve the location from the pack manager (loadInstalled) so it carries a real path."],"exampleFix":"// before\nThemePackManager.resolveInstalledAsset(location, entryName);\n// after\nif (location instanceof ThemePackLocation.File f && f.file() != null) {\n    ThemePackManager.resolveInstalledAsset(location, entryName);\n}","handlingStrategy":"type-guard","validationCode":"if (!(location instanceof ThemePackLocation.Builtin) && location.file() == null) {\n    // surface 'install the pack first' instead of resolving\n    return;\n}","typeGuard":"static boolean resolvable(ThemePackLocation loc) {\n    return loc instanceof ThemePackLocation.Builtin\n        || (loc.file() != null && (Files.isDirectory(loc.file()) || Files.isRegularFile(loc.file())));\n}","tryCatchPattern":"try {\n    ThemePackManager.resolveInstalledAsset(location, entry);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Theme pack location has no readable file\")) {\n    // reinstall/re-resolve the location before retrying\n    }\n}","preventionTips":["Persist enough info to rebuild the location's file path across sessions","Only pass locations obtained from install()/loadInstalled(), never hand-built ones with null files","Check location.file() != null when rendering asset-dependent UI"],"tags":["theme-pack","assets","null-path","resolution"],"backgroundTag":"file-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"}