HMCL-dev/HMCL · error · IllegalArgumentException
Illegal pattern: Missing Key
Error message
Illegal pattern: ${value} Missing Key: ${key} What it means
Thrown as IllegalArgumentException from replaceTokens when a '{Key}' placeholder refers to a variable not present in the tokens (vars) map. The processor profile references data (e.g. a substitution variable) that this install task never populated, so token substitution cannot proceed.
Solutions
- Use the official installer for the target NeoForge/Forge version so placeholder names match what the launcher supplies
- Compare the missing key from the error message against vars populated in NeoForgeOldInstallTask.execute (SIDE, MINECRAFT_JAR, MINECRAFT_VERSION, ROOT, INSTALLER, LIBRARY_DIR, plus profile data)
- Update HMCL — newer profiles may need newer launcher support
- Report the version to HMCL if the official profile still references an unsupported key
Example fix
// before (profile references undefined key)
{CUSTOM_PATCH}
// after (defined key)
{MINECRAFT_JAR} Defensive patterns
Strategy: validation
Validate before calling
// verify all placeholders resolve before running processors
java.util.regex.Matcher m = java.util.regex.Pattern.compile("\\{([^}]+)\\}").matcher(arg);
while (m.find()) if (!vars.containsKey(m.group(1))) throw new IllegalStateException("Missing var: " + m.group(1)); Try / catch
try { task.run(); } catch (IllegalArgumentException e) { if (e.getMessage() != null && e.getMessage().startsWith("Illegal pattern:")) reportMissingVar(e.getMessage()); else throw e; } Prevention
- Keep HMCL updated so newly introduced profile variables are supported
- Only use official installer jars whose placeholders match launcher-supplied vars
- Diff custom profiles against the official one to catch unknown placeholders
When it happens
Trigger: A plain (non fully-bracketed/quoted) processor arg contains {Key} where tokens.containsKey(key) is false — the key is neither in profile.getData()-derived vars nor the injected SIDE/MINECRAFT_JAR/MINECRAFT_VERSION/ROOT/INSTALLER/LIBRARY_DIR entries.
Common situations: Unsupported or modified install_profile.json introducing new placeholders; launcher not supplying a variable expected by a newer Forge/NeoForge processor format; typo in the variable name in a hand-built profile.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Illegal pattern (Bad escape)
- Illegal pattern (Unclosed )
- Artifact name is malformed
- Bad Build-Number
- Expected typed ID prefix '" + expectedPrefix + "'
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/67052d2a2ec26fbb.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOldInstallTask.java:247
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)