google/gson · error · JsonSyntaxException
Missing id or totalSeconds field; at path {path}
Error message
Missing id or totalSeconds field; at path {path} What it means
Thrown by Gson's built-in ZoneId adapter when reading a JSON object that contains neither an 'id' field (for a region-based ZoneId like 'America/New_York') nor a 'totalSeconds' field (for a ZoneOffset). This representation mimics what reflective serialization of java.time.ZoneId produced historically, so it requires one of those two discriminators. The {path} is the reader's previous path.
Source
Thrown at gson/src/main/java/com/google/gson/internal/bind/JavaTimeTypeAdapters.java:319
switch (name) {
case "id":
id = in.nextString();
break;
case "totalSeconds":
totalSeconds = in.nextInt();
break;
default:
// Ignore other fields.
in.skipValue();
}
}
in.endObject();
if (id != null) {
return ZoneId.of(id);
} else if (totalSeconds != null) {
return ZoneOffset.ofTotalSeconds(totalSeconds);
} else {
throw new JsonSyntaxException(
"Missing id or totalSeconds field; at path " + in.getPreviousPath());
}
}
@Override
public void write(JsonWriter out, ZoneId value) throws IOException {
if (value instanceof ZoneOffset) {
out.beginObject();
out.name("totalSeconds");
out.value(((ZoneOffset) value).getTotalSeconds());
out.endObject();
} else {
out.beginObject();
out.name("id");
out.value(value.getId());
out.endObject();
}
}View on GitHub (pinned to 8b8628c656)
Solutions
- Ensure the source emits either {"id":"<zoneId>"} or {"totalSeconds":<int>} for ZoneId/ZoneOffset fields.
- Register a custom TypeAdapter<ZoneId> that accepts the producer's actual encoding (e.g. a bare string via ZoneId.of(s)).
- If migrating from reflection-based output, regenerate the data with the current Gson version so the keys match.
- Pre-validate the JSON object has the required key before deserializing, and surface a clearer error to the data producer.
Example fix
// before: producer sends {"zone":"Z"} -> JsonSyntaxException
// after: register a custom ZoneId adapter that reads the string form
Gson gson = new GsonBuilder()
.registerTypeAdapter(ZoneId.class, new TypeAdapter<ZoneId>() {
@Override public ZoneId read(JsonReader in) throws IOException {
return ZoneId.of(in.nextString());
}
@Override public void write(JsonWriter out, ZoneId v) throws IOException {
out.value(v.getId());
}
}.nullSafe())
.create(); Defensive patterns
Strategy: validation
Validate before calling
// Pre-check JSON has one of the two supported keys for ZoneId
JsonObject o = JsonParser.parseString(json).getAsJsonObject();
if (!o.has("id") && !o.has("totalSeconds")) {
throw new IllegalArgumentException("ZoneId JSON must have 'id' or 'totalSeconds'");
} Try / catch
try {
return gson.fromJson(json, ZoneId.class);
} catch (JsonSyntaxException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Missing id or totalSeconds")) {
// fall back to a string-based ZoneId interpretation
return ZoneId.of(JsonParser.parseString(json).getAsString());
}
throw e;
} Prevention
- Standardize on one ZoneId encoding across producer and consumer.
- Register a custom ZoneId adapter matching the producer's actual format.
- Add contract tests asserting the JSON keys for java.time fields.
When it happens
Trigger: Deserializing a ZoneId or ZoneOffset field whose JSON object omits both keys, e.g. '{}' or '{"foo":"bar"}'. Common when the producer uses a different ZoneId encoding (a bare string like "Z" or "+02:00", or a nested object with different keys) than Gson's reflective integer-fields representation.
Common situations: Interoperating with systems that serialize ZoneId as a plain ISO string; upgrading from older Gson that used reflection and now using the explicit java.time adapter; partial JSON from a trimmed log.
Related errors
- Missing {fieldName} field; at path {path}
- cannot deserialize {baseType} because it does not define a f
- cannot deserialize {baseType} subtype named {label}; did you
- Type adapter '{typeAdapter}' returned wrong type; requested
- JSON document was not fully consumed.
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/0374c81cddb2fe5e.json.
Report an issue: GitHub.