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
- 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.
- Register a custom TypeAdapter<java.sql.Date> with SimpleDateFormat("yyyy-MM-dd") (or your actual format) and set its locale/timezone explicitly.
- Pin the JVM locale or set the format's locale to match the producer to avoid month-abbreviation mismatches.
- 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
- Register a custom TypeAdapter<java.sql.Date> matching the producer's actual format.
- Pin the format locale to avoid month-abbreviation mismatches across regions.
- Prefer java.time.LocalDate for new code; reserve java.sql.Date for JDBC boundaries.
- Contract-test round-trip of date values across locales/timezones.
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
- Failed parsing '{}' as SQL Time; at path {}
- Failed parsing '${s}' as BigInteger; at path ${path}
- Failed parsing '${s}' as InetAddress; at path ${path}; to al
- Failed parsing '${s}' as UUID; at path ${path}
- Failed parsing '${s}' as Currency; at path ${path}
AI-assisted analysis of google/gson@310ac341f2 (2026-08-10).
Data as JSON: /api/errors/acad1435b6fe8988.
Report an issue: GitHub.