HMCL-dev/HMCL · error · IOException
Cannot fix optifine
Error message
Cannot fix optifine
What it means
GameLibrariesTask.execute() wraps an IOException thrown while repairing a known broken Forge+OptiFine combination: it opens the library JAR as a writable zip filesystem and deletes META-INF/mods.toml, and if that zip manipulation fails it rethrows as 'Cannot fix optifine'. The failure means the OptiFine library file could not be patched in place.
Solutions
- Close any program holding the OptiFine JAR open (IDE, file manager, antivirus scan) and retry.
- Delete the OptiFine library file from the libraries folder and let HMCL re-download it.
- Check file write permissions on the libraries directory.
- Remove the OptiFine dependency or update Forge outside the broken range.
Example fix
// before: relying on HMCL to patch the broken pair
optifineLib = detectOptiFine();
installLibraries(...); // may throw 'Cannot fix optifine'
// after: pre-check and re-download a corrupt JAR
if (isOptiFinePair(forgeVersion) && !isUsableZip(optifineFile)) {
Files.delete(optifineFile); // force fresh download before task runs
}
installLibraries(...); Defensive patterns
Strategy: try-catch
Validate before calling
if (forgeVersion != null && FORGE_OPTIFINE_BROKEN_RANGE.contains(VersionNumber.asVersion(forgeVersion)) && !isWritable(file)) closeLockingProcesses(file);
Type guard
boolean isWritableJar(Path p) throws IOException { return Files.isRegularFile(p) && Files.isWritable(p); } Try / catch
try { await(librariesTask); } catch (IOException e) { if (e.getMessage().equals("Cannot fix optifine")) { Files.delete(optifineLib); await(librariesTask); } else throw e; } Prevention
- Avoid combining Forge builds in the known broken range with OptiFine
- Ensure the libraries directory is writable and not on a read-only mount
- Don't open library JARs in other tools while HMCL runs
- Re-download OptiFine if the JAR is corrupt
When it happens
Trigger: The manifest declares Forge within FORGE_OPTIFINE_BROKEN_RANGE (around 1.20.4) together with OptiFine, and CompressingUtils.createWritableZipFileSystem(file) or Files.deleteIfExists throws — e.g. the file is not a zip, is read-only, or is locked by another process.
Common situations: OptiFine JAR corrupted during download, JAR opened/locked by another program (or antivirus on Windows), read-only file permissions, or the path points to a non-zip file.
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
- Game processor file not found, should be downloaded in…
- ForgeVersion files cannot be null
- Minecraft client JAR was not downloaded
- Malformed forge installer file
- Malformed neoforge installer file
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/6bc43e7c4eceb299.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameLibrariesTask.java:174
.injectURLWithCandidates(fmlLib.downloadUrl());
dependencies.add(new FileDownloadTask(uris, file)
.withCounter("hmcl.install.libraries"));
}
}
}
}
Path file = gameRepository.getLayout().getLibraryFile(manifest.id(), library);
if ("optifine".equals(library.groupId()) && Files.exists(file)) {
if (Files.exists(file) && libraries.stream().filter(it -> it.is("optifine", "OptiFine"))
.anyMatch(it -> it.version().startsWith("1.20.4_"))) {
@Nullable String forgeVersion = GameComponentAnalyzer.analyze(manifest, GameVersionNumber.asGameVersion("1.20.4"))
.getVersion(GameComponentType.FORGE);
if (forgeVersion != null && GameComponentAnalyzer.FORGE_OPTIFINE_BROKEN_RANGE.contains(VersionNumber.asVersion(forgeVersion))) {
try (FileSystem fs2 = CompressingUtils.createWritableZipFileSystem(file)) {
Files.deleteIfExists(fs2.getPath("/META-INF/mods.toml"));
} catch (IOException e) {
throw new IOException("Cannot fix optifine", e);
}
}
}
} else if (library.is("org.jackhuang.hmcl", "mmc-bootstrap")) {
if (!Files.exists(file)) {
try (InputStream input = Objects.requireNonNull(
GameLibrariesTask.class.getResourceAsStream(
"/assets/game/HMCLMultiMCBootstrap-1.0.jar"),
"Bundled HMCLMultiMCBootstrap is missing.")) {
Files.createDirectories(file.getParent());
Files.copy(input, file, StandardCopyOption.REPLACE_EXISTING);
}
}
} else if (library.is("org.jackhuang.hmcl", "transformer-discovery-service")) {
try (InputStream input = Objects.requireNonNull(
GameLibrariesTask.class.getResourceAsStream(
"/assets/game/HMCLTransformerDiscoveryService-1.0.jar"),
"Bundled HMCLTransformerDiscoveryService is missing.")) {View on GitHub (pinned to 24702dc5a0)