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

  1. Ensure the source emits either {"id":"<zoneId>"} or {"totalSeconds":<int>} for ZoneId/ZoneOffset fields.
  2. Register a custom TypeAdapter<ZoneId> that accepts the producer's actual encoding (e.g. a bare string via ZoneId.of(s)).
  3. If migrating from reflection-based output, regenerate the data with the current Gson version so the keys match.
  4. 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

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


AI-assisted analysis of google/gson@8b8628c656 (2026-08-04). Data as JSON: /data/errors/0374c81cddb2fe5e.json. Report an issue: GitHub.