google/gson · error · JsonSyntaxException

Failed parsing '{}' as SQL Date; at path {}

Error message

Failed parsing '{}' as SQL Date; at path {}

What it means

Thrown by Gson's SqlDateTypeAdapter when its SimpleDateFormat("MMM d, yyyy") fails to parse the JSON string into java.sql.Date. The default format expects a locale-specific month abbreviation (e.g. "Jan 1, 2020") in the adapter's locale; anything else (ISO date, epoch number, locale mismatch) causes ParseException wrapped as JsonSyntaxException.

Source

Thrown at gson/src/main/java/com/google/gson/internal/sql/SqlDateTypeAdapter.java:69

  private final DateFormat format = new SimpleDateFormat("MMM d, yyyy");

  private SqlDateTypeAdapter() {}

  @Override
  public java.sql.Date read(JsonReader in) throws IOException {
    if (in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    }
    String s = in.nextString();
    synchronized (this) {
      TimeZone originalTimeZone = format.getTimeZone(); // Save the original time zone
      try {
        Date utilDate = format.parse(s);
        return new java.sql.Date(utilDate.getTime());
      } catch (ParseException e) {
        throw new JsonSyntaxException(
            "Failed parsing '" + s + "' as SQL Date; at path " + in.getPreviousPath(), e);
      } finally {
        format.setTimeZone(originalTimeZone); // Restore the original time zone after parsing
      }
    }
  }

  @Override
  public void write(JsonWriter out, java.sql.Date value) throws IOException {
    if (value == null) {
      out.nullValue();
      return;
    }
    String dateString;
    synchronized (this) {
      dateString = format.format(value);
    }
    out.value(dateString);

View on GitHub (pinned to 310ac341f2)

Solutions

  1. Produce JSON strings in the format "MMM d, yyyy" (e.g. "Jan 1, 2020") matching the JVM default locale, OR switch the field to java.util.Date / java.time.LocalDate.
  2. Register a custom TypeAdapter<java.sql.Date> with SimpleDateFormat("yyyy-MM-dd") (or your actual format) and set its locale/timezone explicitly.
  3. Pin the JVM locale or set the format's locale to match the producer to avoid month-abbreviation mismatches.
  4. If the producer emits epoch millis, switch to a numeric adapter.

Example fix

// before
public class Row { public java.sql.Date created; }
// JSON: {"created":"2020-01-01"} -> fails (expects "MMM d, yyyy")

// after: custom adapter for ISO dates
Gson g = new GsonBuilder()
  .registerTypeAdapter(java.sql.Date.class, new TypeAdapter<java.sql.Date>() {
    private final DateFormat f = new SimpleDateFormat("yyyy-MM-dd");
    { f.setTimeZone(TimeZone.getTimeZone("UTC")); }
    public java.sql.Date read(JsonReader in) throws IOException {
      try { return new java.sql.Date(f.parse(in.nextString()).getTime()); }
      catch (ParseException e) { throw new JsonSyntaxException(e); }
    }
    public void write(JsonWriter out, java.sql.Date v) throws IOException { out.value(f.format(v)); }
  }).create();
Defensive patterns

Strategy: validation

Validate before calling

// validate the expected format before parsing, or normalize
private static final Pattern MMM = Pattern.compile("^[A-Za-z]{3} \\d{1,2}, \\d{4}$");
String raw = jsonNode.get("created").getAsString();
if (raw == null || !MMM.matcher(raw).matches()) {
  // either reject, or convert ISO 'yyyy-MM-dd' -> 'MMM d, yyyy'
  throw new IllegalArgumentException("Not 'MMM d, yyyy': " + raw);
}

Try / catch

try {
  return gson.fromJson(json, Row.class);
} catch (JsonSyntaxException e) {
  if (e.getMessage().contains("as SQL Date")) {
    // switch to a custom TypeAdapter<java.sql.Date> with the real format
    throw new IllegalArgumentException("Bad SQL Date format", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Deserializing a field of type java.sql.Date from a JSON string that does not match "MMM d, yyyy" in the running locale: e.g. "2020-01-01" (ISO), "1577836800000" (epoch millis as string), "01/01/2020", or a month abbreviation in a different locale than the JVM default.

Common situations: Mixing java.util.Date (ISO8601 default in Gson) with java.sql.Date ("MMM d, yyyy" default); servers running in different locales producing/expecting different month abbreviations; producers emitting ISO dates or epoch values for sql.Date fields; timezone differences shifting the day.

Related errors


AI-assisted analysis of google/gson@310ac341f2 (2026-08-10). Data as JSON: /api/errors/acad1435b6fe8988. Report an issue: GitHub.