HMCL-dev/HMCL · error · IOException

Unsupported theme-pack entry

Error message

Unsupported theme-pack entry: ${entryName}

What it means

Theme packs allow only the manifest entry and asset entries under 'assets/'. Any other entry name causes checkSupportedThemePackEntry to throw this IOException, enforcing the pack's file layout and preventing unexpected files from being extracted.

Solutions

  1. Repack the zip with only theme-pack.json and an assets/ directory at the root.
  2. Move all media files under assets/ inside the archive.
  3. Exclude OS metadata (e.g. `zip -x '__MACOSX*' '*.DS_Store'`) when creating the archive.
  4. Use ThemePackExporter so only supported entries are written.

Example fix

// before
zip -r pack.zip theme-pack.json assets images/ README.md
// after
zip -r pack.zip theme-pack.json assets -x '*.DS_Store' '__MACOSX*'
Defensive patterns

Strategy: validation

Validate before calling

for (var e : Collections.list(new ZipFile(pack).entries())) {
    String n = e.getName();
    if (!n.equals("theme-pack.json") && !n.equals("assets") && !n.startsWith("assets/")) throw new IllegalArgumentException("unsupported entry: " + n);
}

Try / catch

try {
    ThemePackManager.install(pack, dir);
} catch (IOException e) {
    if (e.getMessage().contains("Unsupported theme-pack entry")) {
      ui.show("Pack contains unsupported files; remove them or re-export via the exporter.");
    } else throw e;
}

Prevention

When it happens

Trigger: Installing a zip containing stray files at the root (README.md, .DS_Store, __MACOSX/,Thumbs.db, license.txt) or assets stored outside the assets/ directory (e.g. 'images/bg.png').

Common situations: macOS Finder zips adding __MACOSX/ and .DS_Store entries; hand-built packs with a top-level 'images' or 'skins' folder; old/experimental layouts from other versions.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/b573f564a9029fec. Report an issue: GitHub.

Appendix: source

Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManager.java:1428

            if (segment.isEmpty() || ".".equals(segment) || "..".equals(segment)) {
                throw new IOException("Theme-pack entry contains an unsafe segment: " + entryName);
            }
            for (int i = 0; i < segment.length(); i++) {
                char ch = segment.charAt(i);
                if (Character.isISOControl(ch) || ch == '\0') {
                    throw new IOException("Theme-pack entry contains a control character: " + entryName);
                }
            }
        }
        return normalized;
    }

    /// Checks that a theme-pack zip entry belongs to the current file layout.
    private static void checkSupportedThemePackEntry(String entryName) throws IOException {
        if (!ThemePackExporter.MANIFEST_ENTRY.equals(entryName)
                && !"assets".equals(entryName)
                && !entryName.startsWith("assets/")) {
            throw new IOException("Unsupported theme-pack entry: " + entryName);
        }
    }

    /// Deletes an existing file, symbolic link, or directory tree.
    private static void deleteIfExists(Path path) throws IOException {
        if (Files.exists(path) || Files.isSymbolicLink(path)) {
            FileUtils.forceDelete(path);
        }
    }

    /// Creates the background model for the current launcher settings.
    private static ThemeBackgroundSettings createCurrentBackground(
            List<ThemePackAsset> assets,
            List<Path> temporaryFiles) throws IOException {
        ResolvedBackground background = resolveCurrentBackground(currentResolveContext());
        Double opacity = background.opacity();
        return switch (background.type()) {
            case DEFAULT -> new ThemeBackgroundSettings(

View on GitHub (pinned to 24702dc5a0)