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
- Inspect the string at the reported offset and correct the timezone marker to Z or +/-.
- Pre-validate the string against an ISO-8601 pattern before deserialization.
- 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
- Reject strings whose timezone slot is not Z or +/- at validation time.
- Use java.time with strict parsers to surface format issues early.
- Run producer/consumer contract tests on date formats.
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
- No time zone indicator
- Mismatching time zone indicator: " + timezoneId + " given, r
- value
- Invalid number: " + value.substring(beginIndex, endIndex)
- Failed parsing '" + s + "' as SQL Date; at path " + in.getPr
AI-assisted analysis of google/gson@8b8628c656 (2026-08-04).
Data as JSON: /data/errors/19592c0d56bf74c8.json.
Report an issue: GitHub.