{"record":{"id":"1843c8e9cc135606","repo":"HMCL-dev/HMCL","slug":"theme-background-without-type-must-contain-only-on","errorCode":null,"errorMessage":"Theme background without type must contain only one source field","messagePattern":"Theme background without type must contain only one source field","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java","lineNumber":89,"sourceCode":"\n        @Nullable String type = readString(object, FIELD_TYPE);\n        @Nullable String id = readString(object, FIELD_ID);\n        @Nullable String path = readString(object, FIELD_PATH);\n        @Nullable String paint = readString(object, FIELD_PAINT);\n\n        if (type == null) {\n            int sourceFields = 0;\n            if (id != null) {\n                sourceFields++;\n            }\n            if (path != null) {\n                sourceFields++;\n            }\n            if (paint != null) {\n                sourceFields++;\n            }\n            if (sourceFields > 1) {\n                throw new JsonParseException(\"Theme background without type must contain only one source field\");\n            }\n            if (id != null) {\n                return new Builtin(id);\n            }\n            if (path != null) {\n                return new Image(path);\n            }\n            if (paint != null) {\n                return new Paint(paint);\n            }\n            return null;\n        }\n\n        return switch (type.trim().replace('-', '_').toUpperCase(Locale.ROOT)) {\n            case \"DEFAULT\" -> new Default();\n            case \"BUILTIN\" -> new Builtin(id);\n            case \"IMAGE\" -> new Image(path);\n            case \"PAINT\" -> new Paint(paint);","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java#L71-L107","documentation":"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.","triggerScenarios":"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\"}.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"id\": \"default_wallpaper\", \"path\": \"assets/bg.png\"}\n// after\n{\"type\": \"image\", \"path\": \"assets/bg.png\"}","handlingStrategy":"validation","validationCode":"long sourceFields = Stream.of(\"id\", \"path\", \"paint\").filter(obj::has).count();\nif (!obj.has(\"type\") && sourceFields > 1) throw new IllegalArgumentException(\"background must have one source field or an explicit type\");","typeGuard":null,"tryCatchPattern":"try { ThemeBackground.fromJson(obj); } catch (JsonParseException e) { LOG.warning(\"Bad background: \" + e.getMessage()); }","preventionTips":["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"],"tags":["json","validation","theme-config","ambiguous-config"],"backgroundTag":"conflicting-config-options","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}