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

  1. Delete the downloaded Java runtime archive and temporary files, then re-download.
  2. Switch download provider/mirror to get the file from a different source.
  3. Verify disk health/free space; retry on a stable connection.
  4. 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

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


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)