kataras/iris · error

invalid offset seconds: %d: %s

Error message

invalid offset seconds: %d: %s

What it means

After parsing the seconds of an unconventional '+HH:MM:SS' offset, adjustForUnconventionalOffset rejects second values greater than 60 (60 allowed only as a leap-second edge case). Larger values mean the offset is malformed and cannot represent a real UTC offset.

Source

Thrown at x/jsonx/iso8601.go:258

	if hours > 24 {
		return time.Time{}, fmt.Errorf("invalid offset hours: %d: %s", hours, offset)
	}

	minutes, err := strconv.Atoi(offsetParts[1])
	if err != nil {
		return time.Time{}, fmt.Errorf("error parsing offset minutes: %s: %w", offset, err)
	}
	if minutes > 60 {
		return time.Time{}, fmt.Errorf("invalid offset minutes: %d: %s", minutes, offset)
	}

	seconds, err := strconv.Atoi(offsetParts[2])
	if err != nil {
		return time.Time{}, fmt.Errorf("error parsing offset seconds: %s: %w", offset, err)
	}

	if seconds > 60 {
		return time.Time{}, fmt.Errorf("invalid offset seconds: %d: %s", seconds, offset)
	}

	totalOffset := time.Duration(sign) * (time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second)
	return t.Add(-totalOffset), nil
}

// UnmarshalJSON parses the "b" into ISO8601 time.
func (t *ISO8601) UnmarshalJSON(b []byte) error {
	if len(b) == 0 {
		return nil
	}

	s := strings.Trim(string(b), `"`)
	tt, err := ParseISO8601(s)
	if err != nil {
		return err
	}

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Correct the offset so seconds are within 0–59 (e.g. '+03:30:00').
  2. Check the producer for width/order bugs when composing the offset.
  3. Validate offsets with a strict regex (^[+-]\d{1,2}:[0-5]\d:[0-5]\d$) before parsing.

Example fix

// before
ParseISO8601("2024-01-02T15:04:05+03:30:99") // invalid offset seconds: 99
// after
ParseISO8601("2024-01-02T15:04:05+03:30:00")
Defensive patterns

Strategy: validation

Validate before calling

var fullOffsetRe = regexp.MustCompile(`^[+-]\d{1,2}:[0-5]\d:[0-5]\d$`)
func hasValidFullOffset(ts string) bool {
	i := strings.LastIndexAny(ts, "+-")
	return i >= 0 && fullOffsetRe.MatchString(ts[i:])
}

Try / catch

tt, err := jsonx.ParseISO8601(s)
if err != nil {
	if strings.Contains(err.Error(), "invalid offset seconds") {
		return fmt.Errorf("timestamp %q has out-of-range offset seconds", s)
	}
	return err
}

Prevention

When it happens

Trigger: ParseISO8601 on a timestamp with an offset like '+03:30:99' — seconds parse as an integer but exceed 60.

Common situations: Serializers concatenating fields incorrectly; corrupted or hand-built timestamps; fuzz/bad-input tests.

Related errors


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