{"record":{"id":"d031f754fc440955","repo":"HMCL-dev/HMCL","slug":"unable-to-move-temp-file-from-temp-to-file","errorCode":null,"errorMessage":"Unable to move temp file from <temp> to <file>","messagePattern":"Unable to move temp file from <temp> to <file>","errorType":"exception","errorClass":"java.io.IOException","httpStatus":null,"severity":"critical","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java","lineNumber":261,"sourceCode":"                try {\n                    for (IntegrityCheckHandler handler : integrityCheckHandlers) {\n                        handler.checkIntegrity(temp, file);\n                    }\n\n                    if (checksum != null && !checksum.isEmpty()) {\n                        String actualChecksum = HexFormat.of().formatHex(digest.digest());\n                        if (!checksum.equalsIgnoreCase(actualChecksum)) {\n                            throw new ChecksumMismatchException(algorithm, checksum, actualChecksum);\n                        }\n                    }\n\n                    Files.createDirectories(file.toAbsolutePath().getParent());\n\n                    try {\n                        Files.move(temp, file, StandardCopyOption.REPLACE_EXISTING);\n                        moved = true;\n                    } catch (Exception e) {\n                        throw new IOException(\"Unable to move temp file from \" + temp + \" to \" + file, e);\n                    }\n\n                    if (caching && algorithm != null) {\n                        try {\n                            repository.cacheFile(file, algorithm, checksum);\n                        } catch (IOException e) {\n                            LOG.warning(\"Failed to cache file\", e);\n                        }\n                    }\n\n                    if (checkETag) {\n                        repository.cacheRemoteFile(response, file);\n                    }\n                } finally {\n                    if (!moved) {\n                        deleteTempFile();\n                    }\n                }","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java#L243-L279","documentation":"FileDownloadTask's close() finalizes a download by atomically moving the temp file to its destination via Files.move(...REPLACE_EXISTING). This IOException wraps any failure during that move, preserving the original cause, since the downloaded data cannot be put in place.","triggerScenarios":"The move fails after a successful download — typically because the destination is locked/open by another process, the target directory permissions changed, or the filesystem is full/read-only (cross-device moves also fail without REPLACE semantics).","commonSituations":"Windows antivirus or another program holding the target .jar open; destination on a read-only or full disk; the file being executed while being replaced; permission changes on the game directory.","solutions":["Close any process locking the destination file (check antivirus, running game, file managers) and retry","Verify write permission on the destination directory and free disk space","Ensure the temp file and destination are on the same filesystem, or perform a copy+delete fallback","Catch the IOException and inspect the wrapped cause for the exact OS error"],"exampleFix":"// before\ndownloadTask.run(); // IOException with wrapped move failure\n// after\ntry {\n    downloadTask.run();\n} catch (IOException e) {\n    LOG.warning(\"Download OK but install failed: \" + e.getCause());\n    Files.deleteIfExists(tempPath);\n}","handlingStrategy":"try-catch","validationCode":"Path target = file.toAbsolutePath();\nFiles.createDirectories(target.getParent());\nif (!Files.isWritable(target.getParent()))\n    throw new AccessDeniedException(\"Destination not writable: \" + target.getParent());","typeGuard":null,"tryCatchPattern":"try {\n    downloadTask.run();\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Unable to move temp file\")) {\n        LOG.warning(\"Install failed: \" + e.getCause());\n        promptUserToCloseLockingProcesses();\n    } else throw e;\n}","preventionTips":["Ensure the destination process (game, antivirus) is not holding target files open","Check disk space and write permissions before starting downloads","Keep temp and destination on the same drive to guarantee atomic moves"],"tags":["file-io","move","download","windows"],"backgroundTag":"file-write-failed","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"}