kataras/iris · error
ISO8601: %w
Error message
ISO8601: %w
What it means
ParseISO8601 parses strings in several ISO-8601 layouts (with/without milliseconds, Z suffix, or +hh:mm offsets, including unconventional hh:mm:ss offsets). When time.Parse (or offset adjustment) rejects the input, the underlying error is wrapped as "ISO8601: %w". It means the string is not in any of the supported ISO-8601 shapes.
Source
Thrown at x/jsonx/iso8601.go:107
)
/*
// Check if the string contains a timezone offset after the 'T' character.
hasOffset := strings.Contains(s, "Z") || (strings.Index(s, "+") > strings.Index(s, "T")) || (strings.Index(s, "-") > strings.Index(s, "T"))
switch {
case strings.HasSuffix(s, "Z"):
tt, err = time.Parse(ISO8601LayoutWithTimezone, s)
case hasOffset && strings.Contains(s, "."):
tt, err = time.Parse(ISO8601ZUTCOffsetLayoutWithMicroseconds, s)
case hasOffset:
tt, err = parseWithOffset(s)
default:
tt, err = time.Parse(ISO8601Layout, s)
}
if err != nil {
return ISO8601{}, fmt.Errorf("ISO8601: %w", err)
}
return ISO8601(tt), nil
*/
if idx := strings.LastIndexFunc(s, startUTCOffsetIndexFunc); idx > 18 { // should have some distance, with and without milliseconds
length := parseSignedOffset(s[idx:])
// Check if the offset is unconventional, e.g., -04:01:19
if offset := s[idx:]; isUnconventionalOffset(offset) {
mainPart := s[:idx]
tt, err = time.Parse("2006-01-02T15:04:05.000000", mainPart)
if err != nil {
return ISO8601{}, fmt.Errorf("ISO8601: %w", err)
}
adjustedTime, parseErr := adjustForUnconventionalOffset(tt, offset)
if parseErr != nil {View on GitHub (pinned to 7bedaf55a0)
Solutions
- Inspect the wrapped %w error (e.g. parsing time ... cannot parse) to see which part of the string failed and fix the producer to emit one of the supported layouts, e.g. time.Time.UTC().Format(time.RFC3339).
- Pre-parse with a custom time.Parse layout that matches the actual input, then convert to jsonx.ISO8601(tt).
- Normalize common variants before parsing (replace space with 'T', append ":00" to short offsets, or handle date-only strings explicitly).
- For UnmarshalJSON failures, use a *string or json.RawMessage field and decode manually with fallback layouts.
Example fix
// before: value "2024-01-02 10:30:00" (space instead of T) var t jsonx.ISO8601 json.Unmarshal(b, &t) // ISO8601: parsing time ... cannot parse // after var raw string json.Unmarshal(b, &raw) normalized := strings.Replace(raw, " ", "T", 1) tt, err := jsonx.ParseISO8601(normalized)
Defensive patterns
Strategy: validation
Validate before calling
func parseISO8601Safe(s string) (jsonx.ISO8601, error) {
s = strings.TrimSpace(s)
s = strings.Replace(s, " ", "T", 1)
if s == "" || s == "null" {
return jsonx.ISO8601{}, nil
}
if re := regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$`); !re.MatchString(s) {
return jsonx.ISO8601{}, fmt.Errorf("unsupported timestamp format: %q", s)
}
return jsonx.ParseISO8601(s)
} Type guard
var isoLayout = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}(:\d{2})?)?$`)
func looksLikeISO8601(s string) bool {
return isoLayout.MatchString(strings.TrimSpace(s))
} Try / catch
if err := json.Unmarshal(b, &ts); err != nil {
var perr *time.ParseError
if errors.As(err, &perr) && strings.HasPrefix(err.Error(), "ISO8601:") {
// log raw value and fall back to a lenient custom-layout parser
}
} Prevention
- Producers should emit RFC3339/ISO-8601 (e.g. JS toISOString(), Go time.RFC3339) — the only shapes ParseISO8601 accepts.
- Validate timestamps with a regex before unmarshalling into jsonx.ISO8601 fields.
- Normalize separators (space→T) and short offsets (+03→+03:00) before parsing third-party data.
- Date-only strings ("2024-01-02") are not supported — handle them with a dedicated date type (e.g. jsonx.SimpleDate).
- Check the wrapped *time.ParseError to identify exactly which layout component mismatched.
When it happens
Trigger: Calling jsonx.ParseISO8601, or json.Unmarshal into a jsonx.ISO8601 field (UnmarshalJSON), or ISO8601.Scan on a string DB value, with a string whose format deviates: wrong layout like "02/01/2006 15:04", date-only "2024-01-02", out-of-range values (month 13), offsets whose parse fails (e.g. malformed +3:00 without zero padding, or a value like +030000), or an offset substring whose hour part is non-numeric.
Common situations: A third-party API changed its date format or sends date-only strings; frontend sends a locale-formatted date instead of toISOString(); a column migrated from timestamp to text now delivers values like "2024-01-02 10:00:00" (space instead of T); timezone offsets like "+03" (no minutes) that the layouts don't cover.
Related errors
- ISO8601: invalid timezone format: %s
- ISO8601: missing timezone offset
- ISO8601: invalid timezone offset length: %s
- ISO8601: invalid timezone offset sign: %c
- invalid offset format: %s
AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30).
Data as JSON: /api/errors/194d6ce1dea4c5e8.
Report an issue: GitHub.