HMCL-dev/HMCL · error · IllegalArgumentException

Illegal pattern: Missing Key:

Error message

Illegal pattern:  Missing Key: 

What it means

When replaceTokens expands a {KEY} token, the key must exist in the vars map built from installer data plus SIDE/MINECRAFT_JAR/MINECRAFT_VERSION/ROOT/INSTALLER/LIBRARY_DIR. If containsKey fails, IllegalArgumentException("Illegal pattern: <value> Missing Key: <key>") is thrown. This indicates the installer references a variable HMCL did not supply.

Solutions

  1. Update HMCL to the latest version so new Forge installer variables are supported
  2. Use a Forge version matching what your HMCL release was built for
  3. Inspect install_profile.json and add the missing value via launcher-side customization if you maintain a fork
  4. Report the missing key to HMCL issue tracker if the installer is official

Example fix

// before (vars lacks key)
vars.put("MINECRAFT_JAR", ...); // but installer uses {MINECRAFT_LIBRARY}
// after
vars.put("MINECRAFT_LIBRARY", FileUtils.getAbsolutePath(libraryDir));
Defensive patterns

Strategy: try-catch

Try / catch

try { installTask.execute(); } catch (IllegalArgumentException e) { if (e.getMessage().contains("Missing Key:")) { String key = e.getMessage().substring(e.getMessage().indexOf("Missing Key:") + 12); updateHMCLAndRetry(key.trim()); } else throw e; }

Prevention

When it happens

Trigger: A processor arg or data literal like "{LIBRARIES}/{foo}" where 'foo' is absent from the vars map — typically a Forge installer using a newer data key than the HMCL version supports.

Common situations: Installing brand-new Forge releases whose install_profile.json introduces data keys not present in the installed HMCL version; running an outdated launcher against bleeding-edge Forge; forked/patched installers referencing custom variables.

Related errors


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

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeNewInstallTask.java:263

                            throw new IllegalArgumentException("Illegal pattern (Bad escape): " + value);
                        key.append(value.charAt(++y));
                    } else {
                        if (c == '{' && d == '}') {
                            x = y;
                            break;
                        }
                        if (c == '\'' && d == '\'') {
                            x = y;
                            break;
                        }
                        key.append(d);
                    }
                }
                if (c == '\'') {
                    buf.append(key);
                } else {
                    if (!tokens.containsKey(key.toString()))
                        throw new IllegalArgumentException("Illegal pattern: " + value + " Missing Key: " + key);
                    buf.append(tokens.get(key.toString()));
                }
            } else {
                buf.append(c);
            }
        }
        return buf.toString();
    }

    private <E extends Exception> String parseLiteral(String literal, Map<String, String> var, ExceptionalFunction<String, String, E> plainConverter) throws E {
        if (StringUtils.isSurrounded(literal, "{", "}"))
            return var.get(StringUtils.removeSurrounding(literal, "{", "}"));
        else if (StringUtils.isSurrounded(literal, "'", "'"))
            return StringUtils.removeSurrounding(literal, "'");
        else if (StringUtils.isSurrounded(literal, "[", "]"))
            return gameRepository.getLayout().getArtifactFile(Artifact.fromDescriptor(StringUtils.removeSurrounding(literal, "[", "]"))).toString();
        else
            return plainConverter.apply(replaceTokens(var, literal));

View on GitHub (pinned to 24702dc5a0)