HMCL-dev/HMCL · error · JsonParseException

Invalid instant:

Error message

Invalid instant: 

What it means

deserializeToInstant tries several DateTimeFormatter patterns (ISO offset/zoned, ISO local date-time) and throws this JsonParseException when none of them can parse the string. The original DateTimeParseException is attached as the cause.

Solutions

  1. Re-serialize the value in ISO-8601 format (Instant.toString() or DateTimeFormatter.ISO_OFFSET_DATE_TIME).
  2. Parse the legacy format yourself with DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.US) and convert to Instant before passing it on.
  3. Check the string for timezone information; ISO_LOCAL_DATE_TIME paths use ZoneId.systemDefault(), so supply an explicit zone when converting.
  4. Confirm no whitespace or locale-specific month/day names are present in the stored value.

Example fix

// before
{"timestamp": "07/03/24 9:06 AM"} // legacy localized format
// after
{"timestamp": "2024-07-03T09:06:00Z"} // ISO-8601
Defensive patterns

Strategy: try-catch

Validate before calling

try {
    Instant.parse(value);
    return true;
} catch (DateTimeParseException e) {
    return false;
}

Try / catch

try {
    return gson.fromJson(json, Instant.class);
} catch (JsonParseException e) {
    // fall back to legacy localized format
    Instant t = LocalDateTime.parse(raw, LEGACY_EN_US_FORMAT).atZone(ZoneId.systemDefault()).toInstant();
}

Prevention

When it happens

Trigger: Deserializing an Instant field whose string value is in an unrecognized format: epoch millis as string, "dd/MM/yyyy HH:mm", a locale-specific EN_US format produced by a different JDK, or a truncated date.

Common situations: Data written by older HMCL versions using the legacy US localized formatter, values saved with a different system default timezone/locale, or hand-edited config timestamps.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/b45fce8893ca0c42. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java:111

    /// Parses an instant from one of the supported textual representations.
    ///
    /// @param string the text to parse
    /// @return the parsed instant
    /// @throws JsonParseException if `string` is not in a supported instant format
    public static Instant deserializeToInstant(String string) {
        try {
            return ZonedDateTime.parse(string, EN_US_FORMAT).toInstant();
        } catch (DateTimeParseException ex1) {
            try {
                ZonedDateTime zonedDateTime = ZonedDateTime.parse(string, ISO_DATE_TIME);
                return zonedDateTime.toInstant();
            } catch (DateTimeParseException e) {
                try {
                    LocalDateTime localDateTime = LocalDateTime.parse(string, ISO_LOCAL_DATE_TIME);
                    return localDateTime.atZone(ZoneId.systemDefault()).toInstant();
                } catch (DateTimeParseException e2) {
                    throw new JsonParseException("Invalid instant: " + string, e);
                }
            }
        }
    }

    /// Formats an instant as an ISO offset date-time string in the given time zone.
    ///
    /// The output is truncated to whole seconds.
    ///
    /// @param instant the instant to format
    /// @param zone    the time zone used to render the instant
    /// @return the formatted instant
    public static String serializeToString(Instant instant, ZoneId zone) {
        return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.ofInstant(instant, zone).truncatedTo(ChronoUnit.SECONDS));
    }
}

View on GitHub (pinned to 24702dc5a0)