HMCL-dev/HMCL · error · ZipException

duplicate entry:

Error message

duplicate entry: 

What it means

Zipper's newEntry de-duplicates entry names: if a name already exists it appends an incrementing suffix (.1, .2, ...); after 100 attempts it gives up and throws ZipException 'duplicate entry: <name>'.

Solutions

  1. Use distinct names/relative paths for each entry (resolve collisions before adding).
  2. Clear or recreate the Zipper if it is being reused across unrelated archives.
  3. Inspect callers for accidental repeated add of the same file (e.g. entry called in a loop with a constant name).
  4. Pre-check the output directory for duplicate filenames differing only by case.

Example fix

// before
zipper.putTextFile("config.json", text);
zipper.putTextFile("config.json", text2); // -> config.json.1 ... eventually ZipException
// after
zipper.putTextFile("config.json", text);
zipper.putTextFile("config2.json", text2);
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
String name = uniqueName(baseName, seen); // append counter if already seen before adding

Try / catch

try {
    zipper.putTextFile(name, text);
} catch (ZipException e) {
    if (e.getMessage().startsWith("duplicate entry:")) {
        zipper.putTextFile(name + "-" + UUID.randomUUID(), text);
    } else throw e;
}

Prevention

When it happens

Trigger: Adding more than ~100 entries resolving to the same name via entry(), putStream(), putLines(), or putTextFile() — e.g. writing many files into the same directory path with identical filenames.

Common situations: Zipping a directory tree that contains duplicate filenames after path flattening; repeatedly adding files of the same name without clearing the zipper; case-insensitive filesystem collisions.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Zipper.java:75

        if (path.startsWith("/"))
            path = path.substring(1);
        if (path.endsWith("/"))
            path = path.substring(0, path.length() - 1);
        return path;
    }

    private ZipEntry newEntry(String name) throws IOException {
        if (entryNames == null || name.endsWith("/") || entryNames.add(name))
            return new ZipEntry(name);

        for (int i = 1; i < 10; i++) {
            String newName = name + "." + i;
            if (entryNames.add(newName)) {
                return new ZipEntry(newName);
            }
        }

        throw new ZipException("duplicate entry: " + name);
    }

    private static String resolve(String dir, String file) {
        if (dir.isEmpty()) return file;
        if (file.isEmpty()) return dir;
        return dir + "/" + file;
    }

    @Override
    public void close() throws IOException {
        zos.close();
    }

    /**
     * Compress all the files in sourceDir
     *
     * @param source    the file in basePath to be compressed
     * @param targetDir the path of the directory in this zip file.

View on GitHub (pinned to 24702dc5a0)