{"record":{"id":"c66c0cd3cbe1c7af","repo":"HMCL-dev/HMCL","slug":"theme-pack-localized-text-must-be-a-string-or-obje","errorCode":null,"errorMessage":"Theme-pack localized text must be a string or object: ${field}","messagePattern":"Theme-pack localized text must be a string or object: (.+?)","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java","lineNumber":224,"sourceCode":"        }\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()) {\n                    throw new JsonParseException(\"Localized text values must be strings: \" + field);\n                }\n                localizedValues.put(\n                        requireNonBlank(entry.getKey(), field),\n                        requireNonBlank(primitive.getAsString(), field));\n            }\n            return new LocalizedText(localizedValues);\n        }\n        throw new JsonParseException(\"Theme-pack localized text must be a string or object: \" + field);\n    }\n\n    /// Returns a validated localized text value.\n    static LocalizedText requireLocalizedText(LocalizedText value, String field) {\n        Objects.requireNonNull(value);\n\n        JsonElement element = JsonUtils.GSON.toJsonTree(value, LocalizedText.class);\n        return parseLocalizedText(element, field);\n    }\n\n    /// Returns a non-blank string value.\n    private static String requireNonBlank(String value, String field) {\n        String trimmed = value.trim();\n        if (trimmed.isEmpty()) {\n            throw new IllegalArgumentException(\"Theme-pack manifest field is blank: \" + field);\n        }\n        return trimmed;\n    }","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java#L206-L242","documentation":"Thrown by parseLocalizedText when a localized text field is neither a JSON string nor a JSON object. Only those two shapes are accepted; arrays, numbers, booleans, or null values for localized fields are rejected, with the field name in the message.","triggerScenarios":"Deserializing a manifest where a localized field is e.g. \"name\": [\"My Theme\"], \"name\": 42, or \"description\": true — any value failing both the JsonPrimitive-string and JsonObject branches.","commonSituations":"Author wrapped the text in an array; a numeric or boolean placeholder was never replaced; a tool serialized localized text in a different representation than the theme-pack format.","solutions":["Use a plain string for non-localized text: \"name\": \"My Theme\".","Or use a locale-to-string object: \"name\": { \"en\": \"My Theme\" }.","Do not use arrays, numbers, booleans, or null for localized fields."],"exampleFix":"// before\n\"name\": [\"My Theme\"]\n// after\n\"name\": \"My Theme\"","handlingStrategy":"validation","validationCode":"JsonElement el = manifestJson.get(\"name\");\nboolean ok = (el instanceof JsonPrimitive p && p.isString()) || el instanceof JsonObject;\nif (!ok) {\n    throw new IllegalArgumentException(\"localized field 'name' must be a string or object\");\n}","typeGuard":"static boolean isValidLocalizedShape(JsonElement el) {\n    return (el instanceof JsonPrimitive p && p.isString()) || el instanceof JsonObject;\n}","tryCatchPattern":"try {\n    ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);\n} catch (JsonParseException e) {\n    // fix the field named in the message to a string or locale map\n}","preventionTips":["Localized text has exactly two shapes: string, or locale-to-string object","Never use arrays, numbers, booleans, or null for localized fields","Validate the manifest shape before zipping the pack"],"tags":["json","i18n","manifest","type-mismatch"],"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"}