HMCL-dev/HMCL · error · IOException
Theme pack does not contain
Error message
Theme pack does not contain
What it means
Thrown by ThemePackManager.load when the target file is not a directory and the zip archive it opens has no regular (non-directory) entry for the manifest (theme.json). A packaged theme pack must ship the manifest, so loading aborts with an IOException.
Solutions
- Repackage the zip so theme.json sits at the archive root (zip the contents, not the parent folder).
- Verify with a zip tool that a regular file entry named theme.json exists at the root.
- Use ThemePackExporter.export to produce a correctly structured pack archive.
- Confirm the file actually is a theme pack and not another launcher archive format.
Example fix
// before (zip layout) mytheme/background.png // after (zip layout) theme.json background.png
Defensive patterns
Strategy: validation
Validate before calling
try (var reader = new ZipArchiveReader(zip)) {
var e = reader.getEntry("theme.json");
if (e == null || e.isDirectory()) throw new IllegalArgumentException("Zip has no root theme.json");
} Try / catch
try { manager.load(zipPath); } catch (IOException e) { if (e.getMessage().startsWith("Theme pack does not contain")) repackageWithRootManifest(); else throw e; } Prevention
- Zip the pack contents so theme.json is at the archive root
- Inspect the archive with a zip listing tool before distributing
- Produce packs with ThemePackExporter instead of manual zipping
When it happens
Trigger: Calling ThemePackManager.load on a zip file that lacks a theme.json entry, or where the manifestEntry exists but manifestEntry.isDirectory() is true (a folder entry named like the manifest).
Common situations: Renaming a resource pack or skin archive to a theme-pack extension, zipping a theme folder incorrectly so the manifest is under an extra top-level folder, or archives created by tools that stored a directory entry named theme.json.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Theme pack directory does not contain
- Invalid theme-pack manifest
- Subdirectory does not exist in the zip file.
- Theme-pack author must be an object or a string
- Missing author name:
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/251f91b39866b35a.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java:388
Path normalizedFile = file.toAbsolutePath().normalize();
try {
if (Files.isDirectory(normalizedFile)) {
Path manifestFile = normalizedFile.resolve(ThemePackExporter.MANIFEST_ENTRY);
if (!Files.isRegularFile(manifestFile)) {
throw new IOException("Theme pack directory does not contain " + ThemePackExporter.MANIFEST_ENTRY);
}
ThemePackManifest manifest = JsonUtils.fromJsonFile(manifestFile, ThemePackManifest.class);
if (manifest == null) {
throw new JsonParseException("Manifest is null");
}
return new LoadedThemePack(normalizedFile, manifest);
}
try (var reader = new ZipArchiveReader(normalizedFile)) {
var manifestEntry = reader.getEntry(ThemePackExporter.MANIFEST_ENTRY);
if (manifestEntry == null || manifestEntry.isDirectory()) {
throw new IOException("Theme pack does not contain " + ThemePackExporter.MANIFEST_ENTRY);
}
ThemePackManifest manifest;
try (var inputStream = reader.getInputStream(manifestEntry)) {
manifest = JsonUtils.fromNonNullJsonFully(inputStream, ThemePackManifest.class);
}
return new LoadedThemePack(normalizedFile, manifest);
}
} catch (JsonParseException | IllegalArgumentException e) {
throw new IOException("Invalid theme-pack manifest", e);
}
}
/// Loads built-in theme pack manifests from launcher resources.
private static @Unmodifiable List<InstalledThemePack> loadBuiltinThemePacks() {
ArrayList<InstalledThemePack> themePacks = new ArrayList<>();
for (String id : BUILTIN_THEME_PACK_IDS) {
try {View on GitHub (pinned to 24702dc5a0)