{"record":{"id":"1c69fda84a746dc5","repo":"HMCL-dev/HMCL","slug":"primary-jar-source-is-not-a-regular-file-source","errorCode":null,"errorMessage":"Primary JAR source is not a regular file: ${source}","messagePattern":"Primary JAR source is not a regular file: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java","lineNumber":565,"sourceCode":"        applied.add(new AppliedFile(target, backup));\n        Files.writeString(target, json);\n    }\n\n    /// Copies a completed primary JAR into its permanent instance location while retaining a\n    /// rollback copy of an existing target.\n    ///\n    /// @param id                the instance receiving the JAR\n    /// @param source            the completed source JAR\n    /// @param rollbackDirectory the directory holding rollback files\n    /// @param applied           rollback records for files already changed\n    /// @throws IOException if the source or target cannot be read or written\n    private void applyPrimaryJar(\n            GameInstanceID id,\n            Path source,\n            Path rollbackDirectory,\n            List<AppliedFile> applied) throws IOException {\n        if (!Files.isRegularFile(source)) {\n            throw new IOException(\"Primary JAR source is not a regular file: \" + source);\n        }\n\n        Path target = getPrimaryJarTarget(id);\n        Files.createDirectories(target.getParent());\n        @Nullable Path backup = backupFile(target, rollbackDirectory, \"jar-\", \".jar\");\n        applied.add(new AppliedFile(target, backup));\n        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);\n    }\n\n    /// Moves an existing target into rollback storage.\n    ///\n    /// @param target            the file about to be replaced\n    /// @param rollbackDirectory the directory holding rollback files\n    /// @param prefix            the backup file prefix\n    /// @param suffix            the backup file suffix\n    /// @return the backup path, or `null` when the target did not exist\n    /// @throws IOException if the target cannot be backed up\n    private static @Nullable Path backupFile(","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/game/DefaultGameRepositoryDraft.java#L547-L583","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the source with Files.isRegularFile(source) before committing","Re-download or re-install the version jar so the file actually exists","Fix the manifest/version JSON jar path to point to the real jar file","If the jar is produced by a prior step, make sure that step succeeded and produced a regular file"],"exampleFix":"// before\nrepo.commit(draft); // source jar path from config is a directory\n// after\nPath jar = Paths.get(config.jarPath());\nif (Files.isRegularFile(jar)) {\n    repo.commit(draft);\n} else {\n    throw new IllegalStateException(\"Not a jar file: \" + jar);\n}","handlingStrategy":"validation","validationCode":"if (!Files.isRegularFile(source)) throw new IllegalStateException(\"Primary jar missing: \" + source);","typeGuard":"static boolean isJarFile(Path p) {\n    return Files.isRegularFile(p) && p.getFileName().toString().endsWith(\".jar\");\n}","tryCatchPattern":"try { repo.commit(draft); }\ncatch (IOException e) { if (e.getMessage().startsWith(\"Primary JAR source is not a regular file\")) { redownloadJar(id); } else throw e; }","preventionTips":["Verify the jar exists and is a regular file after every download step","Keep jar paths relative to the instance root and derive them from the layout","Fix version JSON jar entries that point at directories or stale paths"],"tags":["io","filesystem","jar"],"backgroundTag":"file-not-found","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"}