{"record":{"id":"d751dcd2e737544f","repo":"HMCL-dev/HMCL","slug":"theme-pack-entry-is-empty","errorCode":null,"errorMessage":"Theme-pack entry is empty","messagePattern":"Theme-pack entry is empty","errorType":"validation","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java","lineNumber":1403,"sourceCode":"    /// Moves a file into place, using an atomic move when the platform supports it.\n    private static void moveReplacing(Path source, Path target) throws IOException {\n        try {\n            Files.move(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);\n        } catch (AtomicMoveNotSupportedException e) {\n            Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);\n        }\n    }\n\n    /// Returns a normalized and safe theme-pack zip entry name.\n    private static String normalizeThemePackEntryName(String entryName) throws IOException {\n        Objects.requireNonNull(entryName);\n\n        String normalized = entryName.trim().replace('\\\\', '/');\n        if (normalized.endsWith(\"/\")) {\n            normalized = normalized.substring(0, normalized.length() - 1);\n        }\n        if (normalized.isEmpty()) {\n            throw new IOException(\"Theme-pack entry is empty\");\n        }\n        if (normalized.startsWith(\"/\") || normalized.matches(\"^[A-Za-z]:.*\")) {\n            throw new IOException(\"Theme-pack entry must be relative: \" + entryName);\n        }\n\n        for (String segment : normalized.split(\"/\")) {\n            if (segment.isEmpty() || \".\".equals(segment) || \"..\".equals(segment)) {\n                throw new IOException(\"Theme-pack entry contains an unsafe segment: \" + entryName);\n            }\n            for (int i = 0; i < segment.length(); i++) {\n                char ch = segment.charAt(i);\n                if (Character.isISOControl(ch) || ch == '\\0') {\n                    throw new IOException(\"Theme-pack entry contains a control character: \" + entryName);\n                }\n            }\n        }\n        return normalized;\n    }","sourceCodeStart":1385,"sourceCodeEnd":1421,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java#L1385-L1421","documentation":"normalizeThemePackEntryName trims whitespace, converts backslashes to slashes, and strips one trailing slash from each zip entry name. If nothing remains after that normalization, the entry name is empty and this IOException is thrown. Empty entry names cannot map to a filesystem path.","triggerScenarios":"Installing a theme-pack zip containing an entry whose name is empty, whitespace-only, or just '/'; archives created by buggy tools writing blank-name entries.","commonSituations":"Corrupted or programmatically generated zips with blank entry names; entries consisting only of '/' created by faulty packers.","solutions":["Remove the empty-named entry from the zip (repack excluding it).","Regenerate the archive with a reliable zip tool or ThemePackExporter.","If generating entries programmatically, assert names are non-empty before writing them."],"exampleFix":"// before\nzip.putNextEntry(new ZipArchiveEntry(\"  \"));\n// after\nif (!name.isBlank()) zip.putNextEntry(new ZipArchiveEntry(name.trim().replace('\\\\', '/')));","handlingStrategy":"validation","validationCode":"for (var e : Collections.list(new ZipFile(pack).entries())) {\n    if (e.getName().isBlank() || e.getName().equals(\"/\")) throw new IllegalArgumentException(\"empty entry name in \" + pack);\n}","typeGuard":null,"tryCatchPattern":"try {\n    ThemePackManager.install(pack, dir);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"entry is empty\")) {\n      ui.show(\"Archive is corrupted (blank entry name); re-download or re-export it.\");\n    } else throw e;\n}","preventionTips":["Skip null/blank-named entries when creating zips programmatically.","Regenerate suspicious archives rather than patching them.","Use well-maintained zip tooling."],"tags":["zip","theme-pack","validation"],"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"}