HMCL-dev/HMCL · error · JsonParseException
Theme-pack localized text must be a string or object
Error message
Theme-pack localized text must be a string or object: ${field} What it means
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.
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.
Example fix
// before "name": ["My Theme"] // after "name": "My Theme"
Defensive patterns
Strategy: validation
Validate before calling
JsonElement el = manifestJson.get("name");
boolean ok = (el instanceof JsonPrimitive p && p.isString()) || el instanceof JsonObject;
if (!ok) {
throw new IllegalArgumentException("localized field 'name' must be a string or object");
} Type guard
static boolean isValidLocalizedShape(JsonElement el) {
return (el instanceof JsonPrimitive p && p.isString()) || el instanceof JsonObject;
} Try / catch
try {
ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);
} catch (JsonParseException e) {
// fix the field named in the message to a string or locale map
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Localized text values must be strings
- Theme-pack theme must be an object
- Theme-pack manifest field must be a string
- Localized text field is empty
- Localized text entry cannot be
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/c66c0cd3cbe1c7af.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java:224
}
if (element instanceof JsonObject localizedObject) {
if (localizedObject.isEmpty()) {
throw new JsonParseException("Localized text field is empty: " + field);
}
LinkedHashMap<String, String> localizedValues = new LinkedHashMap<>();
for (Map.Entry<String, JsonElement> entry : localizedObject.entrySet()) {
JsonElement value = entry.getValue();
if (!(value instanceof JsonPrimitive primitive) || !primitive.isString()) {
throw new JsonParseException("Localized text values must be strings: " + field);
}
localizedValues.put(
requireNonBlank(entry.getKey(), field),
requireNonBlank(primitive.getAsString(), field));
}
return new LocalizedText(localizedValues);
}
throw new JsonParseException("Theme-pack localized text must be a string or object: " + field);
}
/// Returns a validated localized text value.
static LocalizedText requireLocalizedText(LocalizedText value, String field) {
Objects.requireNonNull(value);
JsonElement element = JsonUtils.GSON.toJsonTree(value, LocalizedText.class);
return parseLocalizedText(element, field);
}
/// Returns a non-blank string value.
private static String requireNonBlank(String value, String field) {
String trimmed = value.trim();
if (trimmed.isEmpty()) {
throw new IllegalArgumentException("Theme-pack manifest field is blank: " + field);
}
return trimmed;
}View on GitHub (pinned to 24702dc5a0)