HMCL-dev/HMCL · error · JsonParseException
Theme color must be a string or object
Error message
Theme color must be a string or object
What it means
ThemeColorSource.fromJson throws this JsonParseException when the theme color JSON value is neither a string nor a JSON object — for example a number, boolean, array, or null. The parser supports exactly two shapes: a plain color-name string, or an object carrying a "source" field.
Solutions
- Change the value to a color-name string (e.g. "default" or a valid ThemeColor name)
- Or use the object form: {"source": "default"} or {"source": "wallpaper"}
- Fix the manifest generator to serialize the color source via ThemeColorSource.toJsonElement()
Example fix
// before "color": 16711680 // after "color": "default"
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(element instanceof JsonPrimitive p && p.isString()) && !(element instanceof JsonObject)) throw new IllegalArgumentException("theme color must be a string or object"); Type guard
boolean isColorSourceShape(JsonElement el) {
return (el instanceof JsonPrimitive p && p.isString()) || el instanceof JsonObject;
} Try / catch
try { ThemeColorSource.fromJson(el); } catch (JsonParseException e) { LOG.warning("Bad color shape: " + e.getMessage()); src = ThemeColorSource.DEFAULT; } Prevention
- Serialize with ThemeColorSource.toJsonElement() to keep the shape correct
- Use the plain string form for simple cases
- Schema-validate generated manifests before shipping
When it happens
Trigger: fromJson on values like 42, true, ["default"], or [] where a color source is expected in the theme manifest.
Common situations: Programmatically generated manifests writing a numeric color code or a list of colors instead of a string/object; schema drift from another theme format.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Theme background field must be a string:
- Theme color source field must be a string:
- json.toString()
- Protected payload lane is not a string
- Protected payload is not a
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/fb07a195814c8b76.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColorSource.java:73
///
/// @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;
}
if ("WALLPAPER".equals(normalized)) {
return wallpaper();
}
throw new JsonParseException("Unsupported theme color source: " + source);View on GitHub (pinned to 24702dc5a0)