dianping/cat · error · JsonParseException
The date should be a string value
Error message
The date should be a string value
What it means
A Gson JsonParseException thrown by the custom TimestampTypeAdapter registered inside JsonBuilder when deserializing a JSON field into java.sql.Timestamp and the JSON element is not a JsonPrimitive — i.e. the value is an object, array, or null literal instead of a string. The adapter expects dates serialized as "yyyy-MM-dd HH:mm:ss" strings; only the 'not a primitive' shape produces this exact message (an unparseable string yields a wrapped ParseException instead).
Source
Thrown at cat-core/src/main/java/com/dianping/cat/helper/JsonBuilder.java:76
private Gson m_gson = new GsonBuilder().registerTypeAdapter(Timestamp.class, new TimestampTypeAdapter())
.setDateFormat("yyyy-MM-dd HH:mm:ss").setFieldNamingStrategy(m_fieldNamingStrategy).create();
@SuppressWarnings({ "unchecked", "rawtypes" })
public Object parse(String json, Class clz) {
return m_gson.fromJson(json, clz);
}
public String toJson(Object o) {
return m_gson.toJson(o);
}
public class TimestampTypeAdapter implements JsonSerializer<Timestamp>, JsonDeserializer<Timestamp> {
private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
try {
Date date = format.parse(json.getAsString());
return new Timestamp(date.getTime());
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
public JsonElement serialize(Timestamp src, Type arg1, JsonSerializationContext arg2) {
String dateFormatAsString = format.format(new Date(src.getTime()));
return new JsonPrimitive(dateFormatAsString);
}
}
}
View on GitHub (pinned to e815e74d4c)
Solutions
- Inspect the raw JSON for the Timestamp field; confirm it is a quoted "yyyy-MM-dd HH:mm:ss" string.
- Fix the producer to serialize timestamps as strings in that exact format.
- If nulls are legitimate, make the field nullable on the Java side so Gson skips the adapter, or preprocess the JSON replacing null dates with a sentinel string.
- Write your own TypeAdapter that returns null for non-primitive input instead of throwing, and register it on your Gson instance.
Example fix
// before
{"createTime": {"$date":"2026-01-01T00:00:00Z"}} // object -> JsonParseException
// after
{"createTime": "2026-01-01 00:00:00"} Defensive patterns
Strategy: try-catch
Type guard
JsonElement el = jsonObject.get("createTime");
if (el == null || !el.isJsonPrimitive()) { /* treat as null/missing */ } Try / catch
try { obj = jsonBuilder.fromJson(json, type); }
catch (JsonParseException e) { if (e.getMessage().contains("date should be a string")) { /* normalize payload or null the field */ } else throw e; } Prevention
- Standardize on string dates 'yyyy-MM-dd HH:mm:ss' in producers.
- Pre-validate payloads with JsonObject inspection before binding.
- Register a lenient custom TypeAdapter if null/object dates must be tolerated.
When it happens
Trigger: JsonBuilder.fromJson(json, type) (or any Gson parse using this adapter) where a Timestamp-typed field in the payload is {} / [] / null rather than a quoted date string. For example {"createTime": null} or {"createTime": {"$date": ...}} (Mongo-style extended JSON).
Common situations: Consuming JSON from systems that serialize dates as structured objects (BSON extended JSON, Jackson default array [y,m,d,...]) or that emit explicit nulls; changing a field type to Timestamp while old payloads still carry a different shape.
Related errors
AI-assisted analysis of dianping/cat@e815e74d4c (2026-08-14).
Data as JSON: /api/errors/12da3dfa8be0db7a.
Report an issue: GitHub.