kataras/iris · error
ISO8601: invalid timezone offset length: %s
Error message
ISO8601: invalid timezone offset length: %s
What it means
The offset substring found at the end of the timestamp is shorter than the required 6 characters (+HH:MM / -HH:MM), so it cannot be split into sign, hours and minutes. parseOffsetToSeconds rejects anything under 6 bytes before parsing. This guards slice bounds (offsetText[1:3], offsetText[4:6]) from panicking.
Source
Thrown at x/jsonx/iso8601.go:192
}
offsetText := s[idx:]
secondsEastUTC, err := parseOffsetToSeconds(offsetText)
if err != nil {
return time.Time{}, err
}
loc, ok := fixedEastUTCLocations[secondsEastUTC]
if !ok {
loc = time.FixedZone("", secondsEastUTC)
}
return time.ParseInLocation(ISO8601ZUTCOffsetLayoutWithoutMicroseconds, s, loc)
}
func parseOffsetToSeconds(offsetText string) (int, error) {
if len(offsetText) < 6 {
return 0, fmt.Errorf("ISO8601: invalid timezone offset length: %s", offsetText)
}
sign := offsetText[0]
if sign != '-' && sign != '+' {
return 0, fmt.Errorf("ISO8601: invalid timezone offset sign: %c", sign)
}
hours, err := strconv.Atoi(offsetText[1:3])
if err != nil {
return 0, fmt.Errorf("ISO8601: %w", err)
}
minutes, err := strconv.Atoi(offsetText[4:6])
if err != nil {
return 0, fmt.Errorf("ISO8601: %w", err)
}
secondsEastUTC := (hours*60 + minutes) * 60View on GitHub (pinned to 7bedaf55a0)
Solutions
- Provide the offset in full '+HH:MM' form: '2024-01-02T15:04:05+03:00'.
- If input uses compact '+HHMM', normalize by inserting the colon before parsing: s[:len(s)-4]+":'+s[len(s)-4:len(s)-2]+':'+s[len(s)-2:].
- Validate the tail matches ^[+-]\d{2}:\d{2}$ before calling ParseISO8601 and reject/fix bad strings early.
- Check whether an upstream layer truncated the string and fix that producer.
Example fix
// before
tt, err := jsonx.ParseISO8601("2024-01-02T15:04:05+03") // invalid timezone offset length: +03
// after
tt, err := jsonx.ParseISO8601("2024-01-02T15:04:05+03:00") // ok Defensive patterns
Strategy: validation
Validate before calling
var offsetTailRe = regexp.MustCompile(`[+-]\d{2}:\d{2}$`)
func hasValidOffsetTail(s string) bool { return offsetTailRe.MatchString(s) }
// also handle compact form: if regexp `[+-]\d{4}$` matches, insert a colon before parsing Type guard
func offsetTailIsComplete(s string) bool {
i := strings.LastIndexAny(s, "+-")
if i == -1 || len(s)-i < 6 {
return false
}
tail := s[i:]
return tail[3] == ':'
} Try / catch
tt, err := jsonx.ParseISO8601(normalizeOffset(s))
if err != nil {
if strings.Contains(err.Error(), "invalid timezone offset length") {
return fmt.Errorf("timestamp %q: offset must be +HH:MM or -HH:MM", s)
}
return err
} Prevention
- Normalize compact +HHMM offsets to +HH:MM before parsing
- Never truncate timestamp strings when logging or trimming payloads
- Prefer time.Time / time.Format with a fixed layout over hand-built timestamp strings
- Add a table-driven test covering all offset forms your producers emit
When it happens
Trigger: parseWithOffset finds a '+'/'-' via LastIndexFunc and passes the tail to parseOffsetToSeconds, but the tail is too short: e.g. '2024-01-02T15:04:05+03' (offset '+03'), '...+0300' (5 chars, missing colon), or a trailing '-' from a negative-year/odd format like '2024-1-2T15:04:05-'.
Common situations: Timestamps written in '+HHMM' (no colon) compact ISO form; offsets with only hours ('+03') as some APIs emit; strings where the last '-' belongs to the date or a negative number rather than an offset (e.g. '2024-01-02T15:04:05.5-'); hand-written fixtures missing the ':00'.
Related errors
- ISO8601: invalid timezone offset sign: %c
- ISO8601: %w
- ISO8601: invalid timezone format: %s
- ISO8601: missing timezone offset
- invalid offset format: %s
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/efdf773f254bfe46.
Report an issue: GitHub.