{"record":{"id":"7094bc6b8d3c4198","repo":"HMCL-dev/HMCL","slug":"the-instant-should-be-a-string-value","errorCode":null,"errorMessage":"The instant should be a string value","messagePattern":"The instant should be a string value","errorType":"exception","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java","lineNumber":75,"sourceCode":"\n    /// Deserializes a JSON string into an [Instant].\n    ///\n    /// @param json    the JSON element to deserialize\n    /// @param type    the requested target type\n    /// @param context the Gson deserialization context\n    /// @return the parsed instant\n    /// @throws JsonParseException     if `json` is not a string or cannot be parsed as an instant\n    /// @throws IllegalArgumentException if `type` is not [Instant]\n    @Override\n    public Instant deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {\n        if (json instanceof JsonPrimitive) {\n            Instant time = deserializeToInstant(json.getAsString());\n            if (type == Instant.class)\n                return time;\n            else\n                throw new IllegalArgumentException(this.getClass() + \" cannot be deserialized to \" + type);\n        } else {\n            throw new JsonParseException(\"The instant should be a string value\");\n        }\n    }\n\n    /// Formatter for the legacy US localized date-time representation.\n    private static final DateTimeFormatter EN_US_FORMAT = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM)\n            .withLocale(Locale.US)\n            .withZone(ZoneId.systemDefault());\n\n    /// Formatter for ISO local date-time text followed by one of the supported offset forms.\n    private static final DateTimeFormatter ISO_DATE_TIME = new DateTimeFormatterBuilder()\n            .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)\n            .optionalStart().appendOffset(\"+HH:MM\", \"+00:00\").optionalEnd()\n            .optionalStart().appendOffset(\"+H:MM\", \"+0:00\").optionalEnd()\n            .optionalStart().appendOffset(\"+HHMM\", \"+0000\").optionalEnd()\n            .optionalStart().appendOffset(\"+HH\", \"Z\").optionalEnd()\n            .optionalStart().appendOffsetId().optionalEnd()\n            .toFormatter();\n","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/util/gson/InstantTypeAdapter.java#L57-L93","documentation":"InstantTypeAdapter expects the incoming JSON element to be a JSON string (a primitive) that it can parse into a timestamp. This JsonParseException is thrown when the element is an object, array, number, boolean, or null instead of a string.","triggerScenarios":"Deserializing JSON where an Instant-typed field holds a number (epoch millis), a nested object, or null instead of a formatted date-time string.","commonSituations":"APIs or files that serialize timestamps as epoch milliseconds or ISO objects; JSON hand-edited to \"lastLogin\": 1720000000000 instead of a quoted string.","solutions":["Serialize the Instant as a string (InstantTypeAdapter does this via toString/ISO format).","Convert numeric epoch values to a string or to Instant before deserialization.","If null is possible, declare the field as @Nullable Instant or use a null-safe TypeAdapter.","Preprocess the JsonElement to a primitive string before handing it to Gson."],"exampleFix":"// before\n{\"lastLogin\": 1720000000000}\n// after\n{\"lastLogin\": \"2024-07-03T09:06:40Z\"}","handlingStrategy":"validation","validationCode":"JsonElement el = JsonParser.parseString(json);\nif (!(el instanceof JsonPrimitive p) || !p.isString())\n    throw new IllegalArgumentException(\"Instant field must be a JSON string\");","typeGuard":"static boolean isJsonStringInstant(JsonElement el) {\n    return el instanceof JsonPrimitive p && p.isString();\n}","tryCatchPattern":"try {\n    return gson.fromJson(json, Instant.class);\n} catch (JsonParseException e) {\n    log.warn(\"Instant field was not a JSON string\", e);\n}","preventionTips":["Serialize Instants with this adapter so they are written as strings.","Convert epoch-millis timestamps to ISO strings before deserializing.","Make Instant fields nullable explicitly rather than sending JSON null."],"tags":["gson","deserialization","json"],"backgroundTag":"invalid-json-response","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"}