HMCL-dev/HMCL · error · IOException
OptiFine patcher failed, command
Error message
OptiFine patcher failed, command: ${command} What it means
Thrown when the external OptiFine patcher process (java -jar invoking the OptiFine installer against the client jar) exits with a non-zero code. The IOException includes the full command line so the failing invocation can be reproduced.
Solutions
- Re-run with a Java version compatible with the OptiFine installer (usually Java 8+; match the game's requirement).
- Re-download both the client jar and OptiFine installer to rule out corruption.
- Run the exact command printed in the exception manually to see the patcher's own error output.
- Check target paths are writable and not locked by another process.
Example fix
// before
int exitCode = SystemUtils.callExternalProcess(command);
if (exitCode != 0)
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
// after
int exitCode = SystemUtils.callExternalProcess(command);
if (exitCode != 0)
throw new IOException("OptiFine patcher failed (exit " + exitCode + "), command: "
+ new CommandBuilder().addAll(Arrays.asList(command))); Defensive patterns
Strategy: try-catch
Validate before calling
Path javaBin = resolveGameJava(manifest); // ensure Java version matches OptiFine requirement
if (!Files.isRegularFile(minecraftJar) || !Files.isRegularFile(installerFile))
throw new IllegalStateException("inputs missing"); Try / catch
try {
await(task);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("OptiFine patcher failed")) {
// run the embedded command manually to see the patcher's stderr
log.severe(e.getMessage());
}
} Prevention
- Match the JVM version to what the OptiFine installer supports
- Re-download corrupted client jars/installers
- Avoid paths with problematic characters for external processes
- Check the patcher's own output by reproducing the command
When it happens
Trigger: SystemUtils.callExternalProcess(command) returns non-zero while running the OptiFine patch command with [minecraftJar, installerFile, optiFineLibraryPath] — e.g. wrong Java version, incompatible OptiFine/game version combo, corrupted client jar, or file locks.
Common situations: Running the patcher with a too-new/too-old JRE, OptiFine build not matching the Minecraft version, corrupted downloads, or paths with spaces/odd characters breaking the external process.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Game processor exited abnormally with code
- Cannot fix optifine
- File missing
- Minecraft client JAR not found
- Unrecognized installer
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/0f4d321797c29c7c.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java:187
}
// Install launch wrapper modified by OptiFine
boolean hasLaunchWrapper = false;
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installerFile)) {
Path optiFineLibraryPath = gameRepository.getLayout().getLibraryFile(manifest.id(), optiFineLibrary);
if (Files.exists(fs.getPath("optifine/Patcher.class"))) {
String[] command = {
JavaRuntime.getDefault().getBinary().toString(),
"-cp",
installerFile.toString(),
"optifine.Patcher",
minecraftJar.toAbsolutePath().normalize().toString(),
installerFile.toString(),
optiFineLibraryPath.toString()
};
int exitCode = SystemUtils.callExternalProcess(command);
if (exitCode != 0)
throw new IOException("OptiFine patcher failed, command: " + new CommandBuilder().addAll(Arrays.asList(command)));
} else {
FileUtils.copyFile(installerFile, optiFineLibraryPath);
}
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(optiFineLibraryPath)) {
Files.deleteIfExists(fs2.getPath("/META-INF/mods.toml"));
}
Path launchWrapper2 = fs.getPath("launchwrapper-2.0.jar");
if (Files.exists(launchWrapper2)) {
Library launchWrapper = new Library(new Artifact("optifine", "launchwrapper", "2.0"));
Path launchWrapperFile = gameRepository.getLayout().getLibraryFile(manifest.id(), launchWrapper);
Files.createDirectories(launchWrapperFile.toAbsolutePath().getParent());
FileUtils.copyFile(launchWrapper2, launchWrapperFile);
hasLaunchWrapper = true;
libraries.add(launchWrapper);
}
View on GitHub (pinned to 24702dc5a0)