{"record":{"id":"f87e25d5f271e289","repo":"HMCL-dev/HMCL","slug":"theme-pack-manifest-field-must-be-a-string-fiel","errorCode":null,"errorMessage":"Theme-pack manifest field must be a string: ${fieldName}","messagePattern":"Theme-pack manifest field must be a string: (.+?)","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java","lineNumber":197,"sourceCode":"\n        for (Theme theme : themes) {\n            if (theme.id() == null) {\n                throw new IllegalArgumentException(\"Theme ID is required when a theme pack declares multiple themes\");\n            }\n            if (theme.name() == null) {\n                throw new IllegalArgumentException(\"Theme name is required when a theme pack declares multiple themes\");\n            }\n        }\n    }\n\n    /// Reads a required string member.\n    private static String requireMemberString(JsonObject object, String fieldName) {\n        JsonElement element = object.get(fieldName);\n        if (element == null) {\n            throw new JsonParseException(\"Theme-pack manifest is missing \" + fieldName);\n        }\n        if (!(element instanceof JsonPrimitive primitive) || !primitive.isString()) {\n            throw new JsonParseException(\"Theme-pack manifest field must be a string: \" + fieldName);\n        }\n        return requireNonBlank(primitive.getAsString(), fieldName);\n    }\n\n    /// Parses a localized text value.\n    static LocalizedText parseLocalizedText(JsonElement element, String field) {\n        if (element instanceof JsonPrimitive primitive && primitive.isString()) {\n            return LocalizedText.plain(requireNonBlank(primitive.getAsString(), field));\n        }\n        if (element instanceof JsonObject localizedObject) {\n            if (localizedObject.isEmpty()) {\n                throw new JsonParseException(\"Localized text field is empty: \" + field);\n            }\n\n            LinkedHashMap<String, String> localizedValues = new LinkedHashMap<>();\n            for (Map.Entry<String, JsonElement> entry : localizedObject.entrySet()) {\n                JsonElement value = entry.getValue();\n                if (!(value instanceof JsonPrimitive primitive) || !primitive.isString()) {","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java#L179-L215","documentation":"Thrown by requireMemberString when a required manifest member exists but is not a JSON string primitive. Fields such as \"id\" and \"version\" must be plain strings; objects, arrays, numbers, booleans, or null values are rejected with the offending field name in the message.","triggerScenarios":"Deserializing a manifest with \"id\": 123, \"version\": { \"major\": 1 }, or \"id\": null — any case where `object.get(fieldName)` returns a non-string JsonPrimitive or non-primitive.","commonSituations":"Author wrote a version as a number (1.0 instead of \"1.0\"); nested metadata objects from another tool's format pasted into the manifest; a placeholder null left in place of a value.","solutions":["Quote the value so it is a JSON string: \"version\": \"1.0.0\" instead of 1.0.","Flatten any nested object into the expected string form.","Validate the manifest with a JSON schema checker before packaging."],"exampleFix":"// before\n\"version\": 1.0\n// after\n\"version\": \"1.0.0\"","handlingStrategy":"validation","validationCode":"for (String field : new String[]{\"id\", \"version\"}) {\n    JsonElement el = manifestJson.get(field);\n    if (el != null && !(el instanceof JsonPrimitive p && p.isString())) {\n        throw new IllegalArgumentException(field + \" must be a JSON string\");\n    }\n}","typeGuard":"static boolean isStringField(JsonObject manifest, String field) {\n    return manifest.get(field) instanceof JsonPrimitive p && p.isString();\n}","tryCatchPattern":"try {\n    ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);\n} catch (JsonParseException e) {\n    // point the author at the offending field named in the message\n}","preventionTips":["Quote version numbers and IDs in JSON — never emit them as numbers","Avoid null placeholders; omit optional fields entirely instead","Run a JSON schema validator that checks types, not just presence"],"tags":["json","manifest","type-mismatch","theme-pack"],"backgroundTag":"config-type-mismatch","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}