HMCL-dev/HMCL · critical · java.io.IOException
Unable to move temp file from
Error message
Unable to move temp file from <temp> to <file>
What it means
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.
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
Example fix
// before
downloadTask.run(); // IOException with wrapped move failure
// after
try {
downloadTask.run();
} catch (IOException e) {
LOG.warning("Download OK but install failed: " + e.getCause());
Files.deleteIfExists(tempPath);
} Defensive patterns
Strategy: try-catch
Validate before calling
Path target = file.toAbsolutePath();
Files.createDirectories(target.getParent());
if (!Files.isWritable(target.getParent()))
throw new AccessDeniedException("Destination not writable: " + target.getParent()); Try / catch
try {
downloadTask.run();
} catch (IOException e) {
if (e.getMessage().startsWith("Unable to move temp file")) {
LOG.warning("Install failed: " + e.getCause());
promptUserToCloseLockingProcesses();
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to download texture
- Expecting file in terracotta bundle.
- Failed to download theme background: HTTP
- Unsupported checksum type:
- Missing download URI:
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/d031f754fc440955.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java:261
try {
for (IntegrityCheckHandler handler : integrityCheckHandlers) {
handler.checkIntegrity(temp, file);
}
if (checksum != null && !checksum.isEmpty()) {
String actualChecksum = HexFormat.of().formatHex(digest.digest());
if (!checksum.equalsIgnoreCase(actualChecksum)) {
throw new ChecksumMismatchException(algorithm, checksum, actualChecksum);
}
}
Files.createDirectories(file.toAbsolutePath().getParent());
try {
Files.move(temp, file, StandardCopyOption.REPLACE_EXISTING);
moved = true;
} catch (Exception e) {
throw new IOException("Unable to move temp file from " + temp + " to " + file, e);
}
if (caching && algorithm != null) {
try {
repository.cacheFile(file, algorithm, checksum);
} catch (IOException e) {
LOG.warning("Failed to cache file", e);
}
}
if (checkETag) {
repository.cacheRemoteFile(response, file);
}
} finally {
if (!moved) {
deleteTempFile();
}
}View on GitHub (pinned to 24702dc5a0)