{"record":{"id":"0bd1d414c667b0c3","repo":"HMCL-dev/HMCL","slug":"theme-background-field-must-be-a-string","errorCode":null,"errorMessage":"Theme background field must be a string: ","messagePattern":"Theme background field must be a string: ","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java","lineNumber":120,"sourceCode":"\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);\n            case \"THEME_COLOR\" -> new ThemeColor();\n            default -> throw new JsonParseException(\"Unsupported theme background type: \" + type);\n        };\n    }\n\n    /// Reads an optional string field.\n    private static @Nullable String readString(JsonObject object, String field) {\n        JsonElement element = object.get(field);\n        if (element == null) {\n            return null;\n        }\n        if (!(element instanceof JsonPrimitive primitive) || !primitive.isString()) {\n            throw new JsonParseException(\"Theme background field must be a string: \" + field);\n        }\n        return primitive.getAsString();\n    }\n\n    /// Returns a required non-blank string value.\n    private static String requireNonBlank(@Nullable String value, String field) {\n        if (value == null) {\n            throw new JsonParseException(\"Theme background field is missing: \" + field);\n        }\n        String trimmed = value.trim();\n        if (trimmed.isEmpty()) {\n            throw new JsonParseException(\"Theme background field is blank: \" + field);\n        }\n        return trimmed;\n    }\n\n    /// A source that delegates to HMCL's launcher default background resolution.\n    @NotNullByDefault","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemeBackground.java#L102-L138","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"type\": \"image\", \"path\": 42}\n// after\n{\"type\": \"image\", \"path\": \"assets/bg.png\"}","handlingStrategy":"type-guard","validationCode":"for (String f : List.of(\"type\", \"id\", \"path\", \"paint\")) {\n    if (obj.has(f) && !(obj.get(f) instanceof JsonPrimitive p && p.isString())) throw new IllegalArgumentException(\"field must be a string: \" + f);\n}","typeGuard":"boolean isStringField(JsonObject o, String f) {\n    return !o.has(f) || (o.get(f) instanceof JsonPrimitive p && p.isString());\n}","tryCatchPattern":"try { ThemeBackground.fromJson(obj); } catch (JsonParseException e) { LOG.warning(\"Non-string background field: \" + e.getMessage()); }","preventionTips":["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"],"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"}