HMCL-dev/HMCL · error · JsonSyntaxException
Unexpected token
Error message
Unexpected token
What it means
The streaming variant LocalizedText.read (JsonReader-based) accepts null, a string, or an object of string values. If the next token is any other JSON token (BEGIN_ARRAY, NUMBER, BOOLEAN, etc.), it throws a JsonSyntaxException reporting the token.
Solutions
- Fix the JSON so the field is a string, an object of strings, or null.
- Peek the token (reader.peek()) and skip/handle non-supported shapes before calling read.
- Update the producer or adapter so the streaming path matches the actual data shape.
Example fix
// before
{"name": ["Hello"]} // BEGIN_ARRAY hits read()
// after
{"name": "Hello"} // or {"en": "Hello"}, or null Defensive patterns
Strategy: type-guard
Validate before calling
if (reader.peek() != JsonToken.NULL && reader.peek() != JsonToken.STRING && reader.peek() != JsonToken.BEGIN_OBJECT) throw new IllegalStateException("Unsupported token for LocalizedText"); Type guard
static boolean isLocalizedToken(JsonReader r) throws IOException { JsonToken t = r.peek(); return t == JsonToken.NULL || t == JsonToken.STRING || t == JsonToken.BEGIN_OBJECT; } Try / catch
try { return LocalizedText.read(reader); } catch (JsonSyntaxException e) { log.warn("Unexpected token for localized text", e); reader.skipValue(); return null; } Prevention
- Peek the token before reading typed values from streams.
- Keep streaming and tree-based parsers fed the same schema.
- Fix producers that emit arrays for localized fields.
When it happens
Trigger: A JsonReader positioned at a token other than NULL, STRING, or BEGIN_OBJECT when LocalizedText.read is invoked — most commonly an array at a localized-text field.
Common situations: JSON documents whose localized fields hold arrays or numbers; deserializing with the wrong adapter/type after a schema change; corrupted files.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Localized text cannot be empty object
- Localized text entry cannot be
- Localized text field is empty
- Localized text values must be strings
- Theme-pack localized text must be a string or object
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/72997ab5e4451dca.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocalizedText.java:110
jsonReader.nextNull();
return null;
} else if (nextToken == JsonToken.STRING) {
return new LocalizedText(jsonReader.nextString());
} else if (nextToken == JsonToken.BEGIN_OBJECT) {
LinkedHashMap<String, String> localizedValues = new LinkedHashMap<>();
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
String value = jsonReader.nextString();
localizedValues.put(name, value);
}
jsonReader.endObject();
return new LocalizedText(localizedValues);
} else {
throw new JsonSyntaxException("Unexpected token " + nextToken);
}
}
/// Creates a locale-independent text value.
///
/// @param value the text value
/// @return a localized text object that serializes to a JSON string.
public static LocalizedText plain(String value) {
return new LocalizedText(value);
}
/// Locale-independent text used when this instance is not backed by localized values.
private final @Nullable String value;
/// Text values keyed by language keys generated by [LocaleUtils#toLanguageKey(Locale)].
private final @Nullable @Unmodifiable Map<String, String> localizedValues;
/// Creates a locale-independent text value.View on GitHub (pinned to 24702dc5a0)