HMCL-dev/HMCL · error · ArtifactMalformedException
File has incorrect SHA-1 hash: expected , got
Error message
File ${name} has incorrect SHA-1 hash: expected ${expected}, got ${actual} What it means
After decompressing a runtime file, execute() compares the computed SHA-1 with the expected hash from Mojang's manifest. On mismatch it throws ArtifactMalformedException stating expected vs actual hash, preventing an integrity-compromised Java runtime from being installed.
Solutions
- Delete the downloaded Java runtime archive and temporary files, then re-download.
- Switch download provider/mirror to get the file from a different source.
- Verify disk health/free space; retry on a stable connection.
- Update HMCL so the manifest and expected hashes are current.
Example fix
// Recovery, not code: // rm -rf <hmcl-data>/java/<runtime> ; re-run the Java runtime download task
Defensive patterns
Strategy: retry
Validate before calling
// Verify downloaded archive hash against manifest before decompressing
String sha1 = Hashing.sha1().hashBytes(Files.readAllBytes(archive)).toString();
if (!sha1.equalsIgnoreCase(expectedArchiveSha1)) { deleteAndRedownload(); } Type guard
null
Try / catch
try { task.run(); } catch (ArtifactMalformedException e) {
if (e.getMessage().contains("SHA-1")) { purgeRuntimeCache(); retryOnce(); }
} Prevention
- Always verify the top-level archive checksum before extraction.
- Avoid unreliable proxies/CDNs that can alter content.
- Delete old cached runtime archives when Mojang refreshes the manifest.
When it happens
Trigger: Decompressed output's DigestInputStream digest differs from the `rawSha1` recorded in MojangJavaRemoteFiles for that entry (rawSha1 non-null and case-insensitively unequal).
Common situations: Corrupted download (bit flips, truncated archive that still decompresses); CDN/proxy serving modified content; interrupted disk write; rarely, Mojang updating the file without updating clients' cached manifest.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Remote response metadata is unavailable
- Expecting file in terracotta bundle.
- Unsupported checksum type:
- Self verification failed
- SHA-1
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/70519d535a27715c.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDownloadTask.java:132
}
Path tempFile = tempDir.resolve(entry.getKey() + ".lzma");
var task = new FileDownloadTask(downloadProvider.injectURLWithCandidates(download.getUrl()), tempFile,
new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
task.setName(entry.getKey());
dependencies.add(task.thenRunAsync(() -> {
Path decompressed = tempDir.resolve(entry.getKey() + ".tmp");
var digest = MessageDigest.getInstance("SHA-1");
try (var input = new DigestInputStream(new LZMAInputStream(Files.newInputStream(tempFile)), digest)) {
Files.copy(input, decompressed, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new ArtifactMalformedException("File " + entry.getKey() + " is malformed", e);
}
String actualSha1 = HexFormat.of().formatHex(digest.digest());
if (rawSha1 != null && !actualSha1.equalsIgnoreCase(rawSha1)) {
throw new ArtifactMalformedException("File " + entry.getKey() + " has incorrect SHA-1 hash: expected " + rawSha1 + ", got " + actualSha1);
}
try {
Files.deleteIfExists(tempFile);
} catch (IOException e) {
LOG.warning("Failed to delete temporary file: " + tempFile, e);
}
Files.move(decompressed, dest, StandardCopyOption.REPLACE_EXISTING);
if (file.isExecutable()) {
FileUtils.setExecutable(dest);
}
}));
} else if (file.getDownloads().containsKey("raw")) {
DownloadInfo download = file.getDownloads().get("raw");
var task = new FileDownloadTask(downloadProvider.injectURLWithCandidates(download.getUrl()), dest, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
task.setName(entry.getKey());
if (file.isExecutable()) {View on GitHub (pinned to 24702dc5a0)