HMCL-dev/HMCL · error · IOException
Self verification failed
Error message
Self verification failed
What it means
applyUpdate copies the current running JAR over the update target to finalize the update. Before doing so it requires the running JAR to be self-verified (unless DISABLE_SELF_INTEGRITY_CHECK is set); otherwise it throws this IOException, refusing to propagate a binary that could have been tampered with.
Solutions
- Run the official, unmodified HMCL JAR when applying updates
- Rebuild with the official build pipeline so the JAR passes IntegrityChecker
- Check the JAR for accidental modification (e.g. re-zipping breaks the signature) and re-download
- As a last resort for dev builds, set the disable-self-integrity-check property at launch
Example fix
// before java -jar my-custom-build.jar (then applying update fails) // after java -jar HMCL-official.jar // or dev build: java -Dhmcl.self.integrity.check.disable=true -jar my-custom-build.jar
Defensive patterns
Strategy: try-catch
Validate before calling
if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) {
return; // skip applying update on unverified jar
} Try / catch
try {
handler.applyUpdate(target);
} catch (IOException e) {
LOG.severe("Update aborted: running jar failed self verification", e);
// fall back to keeping the current version
} Prevention
- Apply updates only when running the official unmodified JAR
- Keep DISABLE_SELF_INTEGRITY_CHECK unset in production
- Confirm the JAR was not altered (re-signing/re-zipping breaks verification)
When it happens
Trigger: applyUpdate (reached via processArguments) is invoked while IntegrityChecker.isSelfVerified() returns false and DISABLE_SELF_INTEGRITY_CHECK is false.
Common situations: Launching HMCL from a self-compiled or modified JAR and then applying a pending update; a corrupted JAR on disk; running unpacked classes instead of the distributed JAR.
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
- Self verification failed
- Current JAR is not verified
- Unsupported icon file:
- Missing hmcl.lwjgl-unsafe-agent.version attribute
- Malformed modpack configuration
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/816e415261bda3fc.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateHandler.java:175
}
} else {
Exception e = executor.getException();
LOG.warning("Failed to update to " + version, e);
if (!(e instanceof CancellationException)) {
Platform.runLater(() -> Controllers.dialog(e.toString(), i18n("update.failed"), MessageType.ERROR));
}
}
});
}));
}
private static void applyUpdate(Path target) throws IOException {
LOG.info("Applying update to " + target);
Path self = getCurrentLocation();
if (!IntegrityChecker.DISABLE_SELF_INTEGRITY_CHECK && !IntegrityChecker.isSelfVerified()) {
throw new IOException("Self verification failed");
}
ExecutableHeaderHelper.copyWithHeader(self, target);
Optional<Path> newFilename = tryRename(target, Metadata.VERSION);
if (newFilename.isPresent()) {
LOG.info("Move " + target + " to " + newFilename.get());
try {
Files.move(target, newFilename.get());
target = newFilename.get();
} catch (IOException e) {
LOG.warning("Failed to move target", e);
}
}
startJava(target);
}
private static void requestUpdate(Path updateTo, Path self) throws IOException {View on GitHub (pinned to 24702dc5a0)