{"record":{"id":"cc119d10beddb887","repo":"HMCL-dev/HMCL","slug":"localized-text-entry-cannot-be","errorCode":null,"errorMessage":"Localized text entry cannot be ","messagePattern":"Localized text entry cannot be ","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedText.java","lineNumber":68,"sourceCode":"    /// @param element the JSON element to parse, or `null`\n    /// @return the parsed localized text, or `null` if `element` is absent\n    /// @throws JsonParseException if the element is not a primitive or object, the object is empty, or an object entry\n    ///                            is not a primitive value\n    public static @Nullable LocalizedText fromJson(@Nullable JsonElement element) throws JsonParseException {\n        if (element == null || element instanceof JsonNull)\n            return null;\n\n        if (element instanceof JsonObject jsonObject) {\n            if (jsonObject.isEmpty()) {\n                throw new JsonParseException(\"Localized text cannot be empty object\");\n            }\n\n            var map = new LinkedHashMap<String, String>();\n            jsonObject.asMap().forEach((k, v) -> {\n                if (v instanceof JsonPrimitive primitive) {\n                    map.put(k, primitive.getAsString());\n                } else {\n                    throw new JsonParseException(\"Localized text entry cannot be \" + v.getClass());\n                }\n            });\n            return new LocalizedText(map);\n        }\n\n        if (element instanceof JsonPrimitive primitive) {\n            return new LocalizedText(primitive.getAsString());\n        }\n\n        throw new JsonParseException(\"Unexpected json element: \" + element);\n    }\n\n    /// Reads a localized text value from a streaming JSON reader.\n    ///\n    /// The reader accepts JSON `null`, a JSON string, or an object whose values are strings.\n    ///\n    /// @param jsonReader the reader positioned at the next localized text value\n    /// @return the parsed localized text, or `null` if the next token is JSON `null`","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedText.java#L50-L86","documentation":"When parsing a LocalizedText from a JSON object, every entry's value must be a JSON string primitive. If any value is an object, array, number, or boolean, the parser throws a JsonParseException naming the offending value's class.","triggerScenarios":"LocalizedText.fromJson receives a JsonObject where at least one key maps to a non-string value, e.g. {\"en\": \"hi\", \"zh\": {\"nested\": true}} or {\"en\": 42}.","commonSituations":"Hand-edited translation files nesting objects instead of strings; tooling exporting numbers/booleans for localized fields; schema drift after an upstream format change.","solutions":["Make every value in the localized-text object a plain JSON string.","Convert numbers/booleans to strings at the data source before deserialization.","Pre-validate the object: iterate entries and assert v.isJsonPrimitive() && v.getAsJsonPrimitive().isString()."],"exampleFix":"// before\n{\"desc\": {\"en\": \"Hi\", \"count\": 3}}\n\n// after\n{\"desc\": {\"en\": \"Hi\", \"count\": \"3\"}}","handlingStrategy":"validation","validationCode":"for (Map.Entry<String, JsonElement> e : obj.entrySet())\n    if (!(e.getValue() instanceof JsonPrimitive p) || !p.isString())\n        throw new IllegalArgumentException(\"Localized value must be a string: \" + e.getKey());","typeGuard":"static boolean isStringValuedObject(JsonElement el) { return el.isJsonObject() && el.getAsJsonObject().entrySet().stream().allMatch(e -> e.getValue().isJsonPrimitive() && e.getValue().getAsJsonPrimitive().isString()); }","tryCatchPattern":"try { return LocalizedText.fromJson(el); } catch (JsonParseException e) { log.warn(\"Non-string localized entry\", e); return null; }","preventionTips":["Coerce numbers/booleans to strings at the data source.","Add schema validation for translation files.","Review hand-edited translation JSON before shipping."],"tags":["json","i18n","type-mismatch","validation"],"backgroundTag":"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"}