{"record":{"id":"6401e3a5dc20b5bf","repo":"HMCL-dev/HMCL","slug":"theme-color-source-field-must-be-a-string","errorCode":null,"errorMessage":"Theme color source field must be a string: ","messagePattern":"Theme color source field must be a string: ","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColorSource.java","lineNumber":81,"sourceCode":"            if (\"default\".equals(value.trim().replace('-', '_').toLowerCase(Locale.ROOT))) {\n                return DEFAULT;\n            }\n            @Nullable ThemeColor color = ThemeColor.of(value);\n            if (color == null) {\n                throw new JsonParseException(\"Invalid theme color: \" + value);\n            }\n            return custom(color);\n        }\n        if (!(element instanceof JsonObject object)) {\n            throw new JsonParseException(\"Theme color must be a string or object\");\n        }\n\n        JsonElement sourceElement = object.get(FIELD_SOURCE);\n        if (sourceElement == null) {\n            throw new JsonParseException(\"Theme color source is missing required field: \" + FIELD_SOURCE);\n        }\n        if (!(sourceElement instanceof JsonPrimitive sourcePrimitive) || !sourcePrimitive.isString()) {\n            throw new JsonParseException(\"Theme color source field must be a string: \" + FIELD_SOURCE);\n        }\n        String source = sourcePrimitive.getAsString();\n        String normalized = source.trim().replace('-', '_').toUpperCase(Locale.ROOT);\n        if (\"DEFAULT\".equals(normalized)) {\n            return DEFAULT;\n        }\n        if (\"WALLPAPER\".equals(normalized)) {\n            return wallpaper();\n        }\n        throw new JsonParseException(\"Unsupported theme color source: \" + source);\n    }\n\n    /// Converts this color source to its JSON representation.\n    ///\n    /// @return the color source JSON value\n    JsonElement toJsonElement();\n\n    /// Returns the best available color without accessing wallpaper pixels.","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeColorSource.java#L63-L99","documentation":"ThemeColorSource.fromJson throws this JsonParseException when the color source object's \"source\" member exists but is not a JSON string primitive — e.g. a number, boolean, nested object, or array. The source discriminator must be the literal string \"default\" or \"wallpaper\" (case-insensitive, '-' and '_' interchangeable).","triggerScenarios":"fromJson on {\"source\": 1}, {\"source\": true}, {\"source\": [\"default\"]}, or {\"source\": {\"name\":\"default\"}} in the theme manifest's color-source position.","commonSituations":"Generated manifests that emit the source as a numeric enum ordinal or a nested config object instead of its string name; YAML/JSON authoring mistakes.","solutions":["Make \"source\" a string: {\"source\": \"default\"} or {\"source\": \"wallpaper\"}","Fix generators to write the enum name string, not an ordinal or object","Validate the manifest with a JSON schema before loading"],"exampleFix":"// before\n\"color\": {\"source\": 1}\n// after\n\"color\": {\"source\": \"wallpaper\"}","handlingStrategy":"type-guard","validationCode":"if (element instanceof JsonObject o && o.has(\"source\") && !(o.get(\"source\") instanceof JsonPrimitive p && p.isString())) throw new IllegalArgumentException(\"\\\"source\\\" must be a string\");","typeGuard":"boolean hasStringSource(JsonElement el) {\n    return !(el instanceof JsonObject o) || (o.get(\"source\") instanceof JsonPrimitive p && p.isString());\n}","tryCatchPattern":"try { ThemeColorSource.fromJson(el); } catch (JsonParseException e) { LOG.warning(\"Bad source field: \" + e.getMessage()); src = ThemeColorSource.DEFAULT; }","preventionTips":["Write \"source\" as the string \"default\" or \"wallpaper\", never a number or object","Emit enum names, not ordinals, in generated manifests","Validate with a JSON schema enforcing string enums"],"tags":["json","type-mismatch","theme-config"],"backgroundTag":"type-mismatch","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"}