HMCL-dev/HMCL · error · IOException

Unrecognized installer

Error message

Unrecognized installer

What it means

Thrown during install() when the OptiFine installer jar contains no recognizable Config.class at any of the three known locations (root, net/optifine, notch/net/optifine). The installer's structure is not one HMCL can parse to extract MC_VERSION/OF_EDITION/OF_RELEASE.

Solutions

  1. Ensure the file is a genuine OptiFine installer downloaded from optifine.net (e.g. OptiFine_1.20.1_HD_U_I6.jar).
  2. Check the jar contains a Config.class entry (open with an archive tool).
  3. Re-download the installer; avoid unofficial mirrors that serve wrong files.

Example fix

// before
if (!Files.exists(configClass)) throw new IOException("Unrecognized installer");
// after
if (!Files.exists(configClass))
    throw new IOException("Unrecognized installer: " + installer.getFileName()
        + " is not an OptiFine installer (Config.class not found)");
Defensive patterns

Strategy: validation

Validate before calling

try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
    boolean isOptiFine = Files.exists(fs.getPath("Config.class"))
        || Files.exists(fs.getPath("net/optifine/Config.class"))
        || Files.exists(fs.getPath("notch/net/optifine/Config.class"));
    if (!isOptiFine) throw new IllegalArgumentException("Not an OptiFine installer: " + installer);
}

Try / catch

try {
    await(task);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().equals("Unrecognized installer")) {
        // prompt user to select a genuine OptiFine_*_HD_U_*.jar
    }
}

Prevention

When it happens

Trigger: Opening the installer zip and probing for Config.class, net/optifine/Config.class, notch/net/optifine/Config.class — none exist, meaning the file is not actually an OptiFine installer (wrong jar passed as `installer` argument).

Common situations: User selects an arbitrary mod or OptiFabric jar instead of the OptiFine installer, downloads an HTML error page named .jar, or OptiFine changes packaging in future builds.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/5c7f78d1315fd6e6. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineInstallTask.java:271

    /// Creates a task that installs OptiFine from a local installer JAR.
    ///
    /// @param dependencyManager repository-scoped download services
    /// @param manifest           working manifest receiving the OptiFine patch
    /// @param gameVersion       Minecraft version expected by the installation
    /// @param installer         the OptiFine installer JAR
    /// @return the task producing the OptiFine patch
    /// @throws IOException              if the installer is malformed or unsupported
    /// @throws VersionMismatchException if the installer targets another Minecraft version
    public static Task<GameInstancePatch> install(
            DefaultDependencyManager dependencyManager,
            GameInstanceManifest manifest,
            String gameVersion,
            Path installer) throws IOException, VersionMismatchException {
        try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(installer)) {
            Path configClass = fs.getPath("Config.class");
            if (!Files.exists(configClass)) configClass = fs.getPath("net/optifine/Config.class");
            if (!Files.exists(configClass)) configClass = fs.getPath("notch/net/optifine/Config.class");
            if (!Files.exists(configClass)) throw new IOException("Unrecognized installer");
            ConstantPool pool = ConstantPoolScanner.parse(Files.readAllBytes(configClass), ConstantType.UTF8);
            List<String> constants = new ArrayList<>();
            pool.list(Utf8Constant.class).forEach(utf8 -> constants.add(utf8.get()));
            String mcVersion = getOrDefault(constants, constants.indexOf("MC_VERSION") + 1, null);
            String ofEdition = getOrDefault(constants, constants.indexOf("OF_EDITION") + 1, null);
            String ofRelease = getOrDefault(constants, constants.indexOf("OF_RELEASE") + 1, null);

            if (mcVersion == null || ofEdition == null || ofRelease == null)
                throw new IOException("Unrecognized OptiFine installer");

            if (!mcVersion.equals(gameVersion))
                throw new VersionMismatchException(mcVersion, gameVersion);

            OptiFineRemoteVersion remoteVersion = new OptiFineRemoteVersion(
                    mcVersion,
                    ofEdition + "_" + ofRelease,
                    Collections.singletonList(""),
                    false);

View on GitHub (pinned to 24702dc5a0)