HMCL-dev/HMCL · error · JsonParseException
Invalid theme color:
Error message
Invalid theme color:
What it means
ThemeColorSource.fromJson throws this JsonParseException when the theme color is given as a string (not "default") that ThemeColor.of cannot resolve to a known ThemeColor enum constant. The manifest's color name is not one of the launcher's supported named colors, so the seed color cannot be determined.
Solutions
- Replace the string with a valid ThemeColor enum name exactly as defined in the HMCL version in use
- Use "default" if the launcher's built-in seed color is acceptable
- Check available names via ThemeColor.values()/name() and fix spelling/casing
Example fix
// before "color": "blurple" // after "color": "default"
Defensive patterns
Strategy: validation
Validate before calling
String v = element.getAsString();
if (!"default".equalsIgnoreCase(v) && ThemeColor.of(v) == null) throw new IllegalArgumentException("Unknown theme color: " + v); Type guard
boolean isKnownThemeColor(String s) {
return "default".equalsIgnoreCase(s) || ThemeColor.of(s) != null;
} Try / catch
try { ThemeColorSource.fromJson(el); } catch (JsonParseException e) { LOG.warning("Bad color, falling back: " + e.getMessage()); src = ThemeColorSource.DEFAULT; } Prevention
- Only use color names that exist as ThemeColor constants in your HMCL version
- Never put hex codes where an enum name is expected
- Copy names from ThemeColor.values() output, not from memory
When it happens
Trigger: fromJson on a JSON string such as "blurple", "teal-500", or a misspelled name like "deep_purpple" that matches no ThemeColor constant (normalization is trim + '-'->'_' + lowercase for the default check; the color lookup itself is case/name sensitive via ThemeColor.of).
Common situations: Theme authors inventing custom color names, copy-pasting hex codes ("#3b82f6") where an enum name is required, or names from a different HMCL version's color list.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Unsupported theme background type:
- Unsupported protected payload:
- Theme background without type must contain only one source…
- Theme background field must be a string:
- Theme background field is missing:
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/a79c0e098bb009e4.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColorSource.java:68
static ThemeColorSource wallpaper() {
return new Wallpaper();
}
/// Parses a color source from a manifest JSON value.
///
/// @param element the JSON value
/// @return the parsed color source
/// @throws JsonParseException if the color source is malformed
static ThemeColorSource fromJson(JsonElement element) throws JsonParseException {
Objects.requireNonNull(element);
if (element instanceof JsonPrimitive primitive && primitive.isString()) {
String value = primitive.getAsString();
if ("default".equals(value.trim().replace('-', '_').toLowerCase(Locale.ROOT))) {
return DEFAULT;
}
@Nullable ThemeColor color = ThemeColor.of(value);
if (color == null) {
throw new JsonParseException("Invalid theme color: " + value);
}
return custom(color);
}
if (!(element instanceof JsonObject object)) {
throw new JsonParseException("Theme color must be a string or object");
}
JsonElement sourceElement = object.get(FIELD_SOURCE);
if (sourceElement == null) {
throw new JsonParseException("Theme color source is missing required field: " + FIELD_SOURCE);
}
if (!(sourceElement instanceof JsonPrimitive sourcePrimitive) || !sourcePrimitive.isString()) {
throw new JsonParseException("Theme color source field must be a string: " + FIELD_SOURCE);
}
String source = sourcePrimitive.getAsString();
String normalized = source.trim().replace('-', '_').toUpperCase(Locale.ROOT);
if ("DEFAULT".equals(normalized)) {
return DEFAULT;View on GitHub (pinned to 24702dc5a0)