HMCL-dev/HMCL · error · JsonParseException
Theme background without type must contain only one source…
Error message
Theme background without type must contain only one source field
What it means
ThemeBackground.fromJson throws this when the JSON object has no "type" field but contains more than one of the mutually exclusive source fields "id", "path", or "paint". Without a type discriminator the parser infers the source kind from the single source field, so having two or more makes the intent ambiguous. Gson's JsonParseException is thrown to reject the malformed theme background definition.
Solutions
- Remove all but one of the "id", "path", "paint" fields from the background JSON object
- Add an explicit "type" field ("builtin"|"image"|"paint"|"default"|"theme_color") so the source field is unambiguous
- If both fields are genuinely wanted (e.g. fallback), serialize them as separate background settings layers and merge via ThemeBackgroundSettings.merge
Example fix
// before
{"id": "default_wallpaper", "path": "assets/bg.png"}
// after
{"type": "image", "path": "assets/bg.png"} Defensive patterns
Strategy: validation
Validate before calling
long sourceFields = Stream.of("id", "path", "paint").filter(obj::has).count();
if (!obj.has("type") && sourceFields > 1) throw new IllegalArgumentException("background must have one source field or an explicit type"); Try / catch
try { ThemeBackground.fromJson(obj); } catch (JsonParseException e) { LOG.warning("Bad background: " + e.getMessage()); } Prevention
- Keep exactly one of id/path/paint per background object
- Prefer writing an explicit "type" field always
- Use toJsonObject() to generate manifests rather than hand-editing
When it happens
Trigger: Calling ThemeBackground.fromJson (directly or via ThemeBackgroundSettings.fromJson) on a JsonObject that omits "type" yet sets at least two of {"id", "path", "paint"}, e.g. {"id":"wallpaper","path":"bg.png"}.
Common situations: Hand-edited or migrated theme-pack manifest.json files where an author pasted a new background snippet over an old one without removing the previous fields, or copy-merged settings that accumulated multiple source keys.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- Theme background field is blank:
- authlib-injectors.json -> urls cannot be null.
- Missing protected payload member: protection
- Invalid URL:
- code is null
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/1843c8e9cc135606.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java:89
@Nullable String type = readString(object, FIELD_TYPE);
@Nullable String id = readString(object, FIELD_ID);
@Nullable String path = readString(object, FIELD_PATH);
@Nullable String paint = readString(object, FIELD_PAINT);
if (type == null) {
int sourceFields = 0;
if (id != null) {
sourceFields++;
}
if (path != null) {
sourceFields++;
}
if (paint != null) {
sourceFields++;
}
if (sourceFields > 1) {
throw new JsonParseException("Theme background without type must contain only one source field");
}
if (id != null) {
return new Builtin(id);
}
if (path != null) {
return new Image(path);
}
if (paint != null) {
return new Paint(paint);
}
return null;
}
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);View on GitHub (pinned to 24702dc5a0)