HMCL-dev/HMCL · error · IllegalArgumentException
this.getClass() + " cannot be deserialized to " + type
Error message
this.getClass() + " cannot be deserialized to " + type
What it means
InstantTypeAdapter.deserialize parses a JSON string into an Instant, but only returns it when the requested target Type is exactly Instant.class. This IllegalArgumentException signals a configuration/misuse bug: this adapter was registered for a type it is not meant to handle.
Solutions
- Register the adapter only for Instant: gsonBuilder.registerTypeAdapter(Instant.class, new InstantTypeAdapter()).
- Ensure the field/TypeToken being deserialized is declared as java.time.Instant.
- Use a TypeToken<Instant> (not a raw or wildcard type) when calling fromJson.
- If another temporal type is intended, use the appropriate adapter for that type.
Example fix
// before Gson g = new GsonBuilder().registerTypeAdapter(Object.class, new InstantTypeAdapter()).create(); // after Gson g = new GsonBuilder().registerTypeAdapter(Instant.class, new InstantTypeAdapter()).create();
Defensive patterns
Strategy: type-guard
Validate before calling
if (targetType != Instant.class)
throw new IllegalStateException("InstantTypeAdapter only supports Instant, got " + targetType); Type guard
static <T> boolean supportsInstant(TypeToken<T> type) {
return type.getRawType() == Instant.class;
} Try / catch
try {
return gson.fromJson(json, Instant.class);
} catch (IllegalArgumentException e) {
log.error("Instant adapter misconfigured: {}", e.getMessage());
} Prevention
- Register temporal adapters with exact types (registerTypeAdapter(Instant.class, ...)).
- Avoid raw Gson TypeTokens that erase the target type.
- Keep field declarations and adapter registrations in sync.
When it happens
Trigger: Gson deserializing a JSON string where the target TypeToken is not Instant (e.g. LocalDateTime, OffsetDateTime) but this adapter is invoked, typically due to a wrong registerTypeAdapter or a wildcard/raw TypeToken.
Common situations: Registering InstantTypeAdapter for a broader type, using raw Gson without generics so type erasure routes the wrong target to the adapter, or changing a field's declared type from Instant to another temporal type without updating Gson setup.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- json.toString()
- Config is not an object:
- Protected payload is not a
- Expected JsonObject but got
- PortablePath must be a string: " + in.peek()
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/caecad5066b45509.
Report an issue: GitHub.
Appendix: source
Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java:73
return new JsonPrimitive(serializeToString(t, ZoneId.systemDefault()));
}
/// Deserializes a JSON string into an [Instant].
///
/// @param json the JSON element to deserialize
/// @param type the requested target type
/// @param context the Gson deserialization context
/// @return the parsed instant
/// @throws JsonParseException if `json` is not a string or cannot be parsed as an instant
/// @throws IllegalArgumentException if `type` is not [Instant]
@Override
public Instant deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
if (json instanceof JsonPrimitive) {
Instant time = deserializeToInstant(json.getAsString());
if (type == Instant.class)
return time;
else
throw new IllegalArgumentException(this.getClass() + " cannot be deserialized to " + type);
} else {
throw new JsonParseException("The instant should be a string value");
}
}
/// Formatter for the legacy US localized date-time representation.
private static final DateTimeFormatter EN_US_FORMAT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM)
.withLocale(Locale.US)
.withZone(ZoneId.systemDefault());
/// Formatter for ISO local date-time text followed by one of the supported offset forms.
private static final DateTimeFormatter ISO_DATE_TIME = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+H:MM", "+0:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
.optionalStart().appendOffsetId().optionalEnd()View on GitHub (pinned to 24702dc5a0)