{"id":"6f4ff1629ab21a3b","repo":"google/gson","slug":"failed-parsing-s-as-sql-date-at-path","errorCode":null,"errorMessage":"Failed parsing '\" + s + \"' as SQL Date; at path \" + in.getPreviousPath()","messagePattern":"Failed parsing '\" \\+ s \\+ \"' as SQL Date; at path \" \\+ in\\.getPreviousPath\\(\\)","errorType":"exception","errorClass":"JsonSyntaxException","httpStatus":null,"severity":"error","filePath":"gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java","lineNumber":69,"sourceCode":"\n  private final DateFormat format = new SimpleDateFormat(\"MMM d, yyyy\");\n\n  private SqlDateTypeAdapter() {}\n\n  @Override\n  public java.sql.Date read(JsonReader in) throws IOException {\n    if (in.peek() == JsonToken.NULL) {\n      in.nextNull();\n      return null;\n    }\n    String s = in.nextString();\n    synchronized (this) {\n      TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone\n      try {\n        Date utilDate = format.parse(s);\n        return new java.sql.Date(utilDate.getTime());\n      } catch (ParseException e) {\n        throw new JsonSyntaxException(\n            \"Failed parsing '\" + s + \"' as SQL Date; at path \" + in.getPreviousPath(), e);\n      } finally {\n        format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing\n      }\n    }\n  }\n\n  @Override\n  public void write(JsonWriter out, java.sql.Date value) throws IOException {\n    if (value == null) {\n      out.nullValue();\n      return;\n    }\n    String dateString;\n    synchronized (this) {\n      dateString = format.format(value);\n    }\n    out.value(dateString);","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/google/gson/blob/8b8628c65699bc4421696183c62ae0c1b9b281dc/gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java#L51-L87","documentation":"SqlDateTypeAdapter parses the JSON string with SimpleDateFormat(\"MMM d, yyyy\") (e.g. 'Jan 1, 2024'). A ParseException is wrapped as JsonSyntaxException. The format is locale and timezone sensitive and is synchronized on the adapter.","triggerScenarios":"Deserializing a JSON value into a java.sql.Date field where the string is not in the expected 'MMM d, yyyy' format (e.g. '2024-01-01', ISO format, or a locale-incompatible month abbreviation).","commonSituations":"Producer emits ISO-8601 or 'yyyy-MM-dd' but Gson's sql.Date adapter expects the long month form; running under a non-English locale where 'Jan' is not a valid month; or mismatched date conventions between layers.","solutions":["Provide the date string in 'MMM d, yyyy' form, matching the default adapter.","Register a custom TypeAdapter<java.sql.Date> using the format your producer emits (e.g. 'yyyy-MM-dd') and the desired Locale/TimeZone.","Deserialize as java.util.Date or java.time.LocalDate instead and convert, if the SQL type is not essential."],"exampleFix":"// before\njava.sql.Date d = gson.fromJson(\"\\\"2024-01-01\\\"\", java.sql.Date.class);\n\n// after\nGson gson = new GsonBuilder().registerTypeAdapter(java.sql.Date.class, new TypeAdapter<java.sql.Date>() {\n    private final java.text.DateFormat f = new java.text.SimpleDateFormat(\"yyyy-MM-dd\");\n    @Override public java.sql.Date read(JsonReader in) throws IOException { return java.sql.Date.valueOf(in.nextString()); }\n    @Override public void write(JsonWriter out, java.sql.Date v) throws IOException { out.value(v.toString()); }\n}).create();","handlingStrategy":"validation","validationCode":"boolean isSqlDateParsable(String s) {\n  if (s == null) return false;\n  try { java.text.DateFormat f = new java.text.SimpleDateFormat(\"MMM d, yyyy\", Locale.ENGLISH); f.parse(s); return true; }\n  catch (java.text.ParseException e) { return false; }\n}","typeGuard":"static boolean matchesDefaultSqlDateFormat(String s) {\n  return s != null && s.matches(\"[A-Z][a-z]{2} \\\\d{1,2}, \\\\d{4}\");\n}","tryCatchPattern":"try {\n  java.sql.Date d = gson.fromJson(json, java.sql.Date.class);\n} catch (JsonSyntaxException e) {\n  // parse with a custom format adapter instead\n}","preventionTips":["Register a java.sql.Date adapter matching your producer format (and Locale).","Pin Locale.ENGLISH for the adapter to avoid host-locale surprises.","Prefer java.time.LocalDate for new code."],"tags":["gson","deserialization","sql-date","date-parsing","locale","json"],"analyzedSha":"8b8628c65699bc4421696183c62ae0c1b9b281dc","analyzedAt":"2026-08-04T19:12:22.202Z","schemaVersion":2}