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) * 60

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Provide the offset in full '+HH:MM' form: '2024-01-02T15:04:05+03:00'.
  2. 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:].
  3. Validate the tail matches ^[+-]\d{2}:\d{2}$ before calling ParseISO8601 and reject/fix bad strings early.
  4. 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

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


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/efdf773f254bfe46. Report an issue: GitHub.