HMCL-dev/HMCL · error · JsonParseException
Theme background field must be a string:
Error message
Theme background field must be a string:
What it means
ThemeBackground.readString throws this JsonParseException when a known background field ("type", "id", "path", or "paint") is present in the JSON object but is not a JSON string primitive (e.g. a number, boolean, object, or array). The parser only accepts string values for these fields; any other JSON shape is rejected with the field name appended to the message.
Solutions
- Quote the field value so it is a JSON string: {"path": "assets/bg.png"}
- For "paint", supply the serialized paint string (e.g. a JavaFX paint definition), not a nested object
- Remove the field entirely if it is not needed — absent fields are legal, wrong-typed ones are not
Example fix
// before
{"type": "image", "path": 42}
// after
{"type": "image", "path": "assets/bg.png"} Defensive patterns
Strategy: type-guard
Validate before calling
for (String f : List.of("type", "id", "path", "paint")) {
if (obj.has(f) && !(obj.get(f) instanceof JsonPrimitive p && p.isString())) throw new IllegalArgumentException("field must be a string: " + f);
} Type guard
boolean isStringField(JsonObject o, String f) {
return !o.has(f) || (o.get(f) instanceof JsonPrimitive p && p.isString());
} Try / catch
try { ThemeBackground.fromJson(obj); } catch (JsonParseException e) { LOG.warning("Non-string background field: " + e.getMessage()); } Prevention
- Always quote string fields in hand-edited JSON
- Pass paint as its serialized string form, not an object
- Validate manifests with a JSON schema before release
When it happens
Trigger: fromJson encounters {"path": 123}, {"id": true}, {"paint": {"color":"red"}}, or {"type": ["image"]} — any non-string JSON primitive or structured value in one of the four fields.
Common situations: Theme authors quoting incorrectly or generating manifests programmatically where a value was left unquoted or emitted as a number/boolean; also happens when nesting a paint object instead of passing its serialized string form.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Theme color must be a string or object
- 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/0bd1d414c667b0c3.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java:120
return switch (type.trim().replace('-', '_').toUpperCase(Locale.ROOT)) {
case "DEFAULT" -> new Default();
case "BUILTIN" -> new Builtin(id);
case "IMAGE" -> new Image(path);
case "PAINT" -> new Paint(paint);
case "THEME_COLOR" -> new ThemeColor();
default -> throw new JsonParseException("Unsupported theme background type: " + type);
};
}
/// Reads an optional string field.
private static @Nullable String readString(JsonObject object, String field) {
JsonElement element = object.get(field);
if (element == null) {
return null;
}
if (!(element instanceof JsonPrimitive primitive) || !primitive.isString()) {
throw new JsonParseException("Theme background field must be a string: " + field);
}
return primitive.getAsString();
}
/// Returns a required non-blank string value.
private static String requireNonBlank(@Nullable String value, String field) {
if (value == null) {
throw new JsonParseException("Theme background field is missing: " + field);
}
String trimmed = value.trim();
if (trimmed.isEmpty()) {
throw new JsonParseException("Theme background field is blank: " + field);
}
return trimmed;
}
/// A source that delegates to HMCL's launcher default background resolution.
@NotNullByDefaultView on GitHub (pinned to 24702dc5a0)