HMCL-dev/HMCL · error · IOException

Primary JAR source is not a regular file

Error message

Primary JAR source is not a regular file: ${source}

What it means

applyPrimaryJar validates that the source JAR to install as the instance's primary jar is a regular file before copying/backing it up. The library throws IOException when the given source path is missing, a directory, or otherwise not a normal file. This protects commit() from copying directories or special files into the instance's jar slot.

Solutions

  1. Verify the source with Files.isRegularFile(source) before committing
  2. Re-download or re-install the version jar so the file actually exists
  3. Fix the manifest/version JSON jar path to point to the real jar file
  4. If the jar is produced by a prior step, make sure that step succeeded and produced a regular file

Example fix

// before
repo.commit(draft); // source jar path from config is a directory
// after
Path jar = Paths.get(config.jarPath());
if (Files.isRegularFile(jar)) {
    repo.commit(draft);
} else {
    throw new IllegalStateException("Not a jar file: " + jar);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Files.isRegularFile(source)) throw new IllegalStateException("Primary jar missing: " + source);

Type guard

static boolean isJarFile(Path p) {
    return Files.isRegularFile(p) && p.getFileName().toString().endsWith(".jar");
}

Try / catch

try { repo.commit(draft); }
catch (IOException e) { if (e.getMessage().startsWith("Primary JAR source is not a regular file")) { redownloadJar(id); } else throw e; }

Prevention

When it happens

Trigger: commit() calling applyPrimaryJar with a source path that does not exist, points to a directory, or is a device/symlink-to-non-regular-file — commonly a downloaded or version jar path that is wrong.

Common situations: Failed or partial game download left no jar; version JSON points at a directory or wrong filename; user manually replaced the jar with a folder; network installer produced an empty path.

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


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java:565

        applied.add(new AppliedFile(target, backup));
        Files.writeString(target, json);
    }

    /// Copies a completed primary JAR into its permanent instance location while retaining a
    /// rollback copy of an existing target.
    ///
    /// @param id                the instance receiving the JAR
    /// @param source            the completed source JAR
    /// @param rollbackDirectory the directory holding rollback files
    /// @param applied           rollback records for files already changed
    /// @throws IOException if the source or target cannot be read or written
    private void applyPrimaryJar(
            GameInstanceID id,
            Path source,
            Path rollbackDirectory,
            List<AppliedFile> applied) throws IOException {
        if (!Files.isRegularFile(source)) {
            throw new IOException("Primary JAR source is not a regular file: " + source);
        }

        Path target = getPrimaryJarTarget(id);
        Files.createDirectories(target.getParent());
        @Nullable Path backup = backupFile(target, rollbackDirectory, "jar-", ".jar");
        applied.add(new AppliedFile(target, backup));
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /// Moves an existing target into rollback storage.
    ///
    /// @param target            the file about to be replaced
    /// @param rollbackDirectory the directory holding rollback files
    /// @param prefix            the backup file prefix
    /// @param suffix            the backup file suffix
    /// @return the backup path, or `null` when the target did not exist
    /// @throws IOException if the target cannot be backed up
    private static @Nullable Path backupFile(

View on GitHub (pinned to 24702dc5a0)