google/gson · error · IndexOutOfBoundsException

Invalid time zone indicator {timezoneIndicator}

Error message

Invalid time zone indicator {timezoneIndicator}

What it means

Thrown internally by UtcDateTypeAdapter's parser when the character at the expected timezone position is not one of 'Z', '+', or '-'. The parser only accepts those three indicators; any other character (a letter, a digit, a space) is treated as an invalid indicator. This IndexOutOfBoundsException is caught and rethrown as a ParseException, then wrapped as JsonParseException by read().

Source

Thrown at extras/src/main/java/com/google/gson/typeadapters/UtcDateTypeAdapter.java:204

          }
        }
      }

      // extract timezone
      String timezoneId;
      if (date.length() <= offset) {
        throw new IllegalArgumentException("No time zone indicator");
      }
      char timezoneIndicator = date.charAt(offset);
      if (timezoneIndicator == '+' || timezoneIndicator == '-') {
        String timezoneOffset = date.substring(offset);
        timezoneId = GMT_ID + timezoneOffset;
        offset += timezoneOffset.length();
      } else if (timezoneIndicator == 'Z') {
        timezoneId = GMT_ID;
        offset += 1;
      } else {
        throw new IndexOutOfBoundsException("Invalid time zone indicator " + timezoneIndicator);
      }

      TimeZone timezone = TimeZone.getTimeZone(timezoneId);
      if (!timezone.getID().equals(timezoneId)) {
        throw new IndexOutOfBoundsException();
      }

      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);

View on GitHub (pinned to 8b8628c656)

Solutions

  1. Convert named/offset zones to the supported form: replace "UTC"/"GMT" with "Z", replace "PST" with "-08:00", etc., before parsing.
  2. Use a lenient SimpleDateFormat or java.time parser that accepts zone names if you must consume such input, instead of UtcDateTypeAdapter.
  3. Sanitize the input string with a regex/replace step that normalizes the trailing timezone token.
  4. Validate the format against ^.*[Z+-]$ at the timezone position before handing off.

Example fix

// before
String json = "\"2024-01-01T12:00:00 UTC\"";
Date d = gson.fromJson(json, Date.class); // throws: ' ' is invalid indicator

// after
String json = "\"2024-01-01T12:00:00Z\"";
Date d = gson.fromJson(json, Date.class);
Defensive patterns

Strategy: validation

Validate before calling

// Normalize named zones to offset form before parsing
static String normalizeZone(String date) {
  date = date.replaceAll("(?i)\\s*(UTC|GMT)$", "Z");
  // Map common named zones to offsets (extend as needed)
  date = date.replaceAll("(?i)\\sPST$", "-08:00");
  date = date.replaceAll("(?i)\\sPDT$", "-07:00");
  if (!date.matches(".*[Zz]$|.*/[+-]\\d{2}:?\\d{2}$")) {
    throw new IllegalArgumentException("Unrecognized timezone in: " + date);
  }
  return date;
}

Type guard

static boolean hasValidTimezoneIndicator(String date) {
  if (date == null || date.isEmpty()) return false;
  char c = date.charAt(date.length() - 1);
  return c == 'Z' || c == 'z' || date.matches(".*[+-]\\d{2}:?\\d{2}$");
}

Try / catch

try {
  Date d = gson.fromJson(json, Date.class);
} catch (JsonParseException e) {
  Throwable c = e.getCause();
  if (c != null && c.getMessage() != null && c.getMessage().contains("Invalid time zone indicator")) {
    // normalize the zone token and retry, or reject the payload
  } else throw e;
}

Prevention

When it happens

Trigger: Date strings like "2024-01-01T12:00:00X", "2024-01-01T12:00:00 UTC", or "2024-01-01T12:00:00GMT" where a non-standard token sits at the timezone slot; corrupted or hand-edited timestamps; locale-specific formats that spell out the zone.

Common situations: Third-party APIs returning non-strict ISO-8601 (named zones like "PST", "EST", "UTC" spelled out); legacy systems emitting "GMT" literally; encoding issues inserting stray characters; copy-paste errors.

Related errors


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