google/gson · error · IndexOutOfBoundsException

Invalid time zone indicator '" + timezoneIndicator + "'

Error message

Invalid time zone indicator '" + timezoneIndicator + "'

What it means

ISO8601Utils reaches the timezone position but the character there is not 'Z', '+', or '-', indicating a structurally malformed date string. It throws IndexOutOfBoundsException 'Invalid time zone indicator'.

Source

Thrown at gson/src/main/java/com/google/gson/internal/bind/util/ISO8601Utils.java:279

          String act = timezone.getID();
          if (!act.equals(timezoneId)) {
            /* 22-Jan-2015, tatu: Looks like canonical version has colons, but we may be given
             *    one without. If so, don't sweat.
             *   Yes, very inefficient. Hopefully not hit often.
             *   If it becomes a perf problem, add 'loose' comparison instead.
             */
            String cleaned = act.replace(":", "");
            if (!cleaned.equals(timezoneId)) {
              throw new IndexOutOfBoundsException(
                  "Mismatching time zone indicator: "
                      + timezoneId
                      + " given, resolves to "
                      + timezone.getID());
            }
          }
        }
      } else {
        throw new IndexOutOfBoundsException(
            "Invalid time zone indicator '" + timezoneIndicator + "'");
      }

      Calendar calendar = new GregorianCalendar(timezone);
      calendar.setLenient(false);
      calendar.set(Calendar.YEAR, year);
      calendar.set(Calendar.MONTH, month - 1);
      calendar.set(Calendar.DAY_OF_MONTH, day);
      calendar.set(Calendar.HOUR_OF_DAY, hour);
      calendar.set(Calendar.MINUTE, minutes);
      calendar.set(Calendar.SECOND, seconds);
      calendar.set(Calendar.MILLISECOND, milliseconds);

      pos.setIndex(offset);
      return calendar.getTime();
      // If we get a ParseException it'll already have the right message/offset.
      // Other exception types can convert here.
    } catch (IndexOutOfBoundsException | IllegalArgumentException e) {

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Inspect the string at the reported offset and correct the timezone marker to Z or +/-.
  2. Pre-validate the string against an ISO-8601 pattern before deserialization.
  3. Register a custom TypeAdapter<Date> using a more lenient parser.

Example fix

// before
Date d = gson.fromJson("\"2024-01-01T00:00:00X\"", Date.class);

// after
String s = source.substring(0, source.length() - 1) + "Z";
Date d = gson.fromJson('"' + s + '"', Date.class);
Defensive patterns

Strategy: validation

Validate before calling

boolean hasValidTimezoneIndicatorChar(String iso) {
  if (iso == null || iso.isEmpty()) return false;
  char c = iso.charAt(iso.length() - 1);
  if (c == 'Z') return true;
  return iso.matches(".*[+\\-][0-9]{2}:?[0-9]{2}$");
}

Type guard

static boolean endsWithIsoTimezone(String iso) {
  return iso != null && (iso.endsWith("Z") || iso.matches(".*[+\\-]\\d{2}:?\\d{2}$"));
}

Try / catch

try {
  Date d = gson.fromJson(json, Date.class);
} catch (JsonSyntaxException e) {
  // strip stray trailing chars, append Z, retry
}

Prevention

When it happens

Trigger: A date string where the timezone slot is occupied by an unexpected character, e.g. trailing 'X', a letter, or a stray separator after the time component.

Common situations: Truncated/garbled date strings, mixed formats, or a producer that emits a non-ISO marker at the end.

Related errors


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