{"record":{"id":"2c2bc49620b3659e","repo":"kataras/iris","slug":"iso8601-invalid-timezone-format-s","errorCode":null,"errorMessage":"ISO8601: invalid timezone format: %s","messagePattern":"ISO8601: invalid timezone format: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/jsonx/iso8601.go","lineNumber":132,"sourceCode":"\t\tlength := parseSignedOffset(s[idx:])\n\n\t\t// Check if the offset is unconventional, e.g., -04:01:19\n\t\tif offset := s[idx:]; isUnconventionalOffset(offset) {\n\t\t\tmainPart := s[:idx]\n\t\t\ttt, err = time.Parse(\"2006-01-02T15:04:05.000000\", mainPart)\n\t\t\tif err != nil {\n\t\t\t\treturn ISO8601{}, fmt.Errorf(\"ISO8601: %w\", err)\n\t\t\t}\n\n\t\t\tadjustedTime, parseErr := adjustForUnconventionalOffset(tt, offset)\n\t\t\tif parseErr != nil {\n\t\t\t\treturn ISO8601{}, fmt.Errorf(\"ISO8601: %w\", parseErr)\n\t\t\t}\n\t\t\treturn ISO8601(adjustedTime), nil\n\t\t}\n\n\t\tif idx+1 > idx+length || len(s) <= idx+length+1 {\n\t\t\treturn ISO8601{}, fmt.Errorf(\"ISO8601: invalid timezone format: %s\", s[idx:])\n\t\t}\n\n\t\toffsetText := s[idx+1 : idx+length]\n\t\toffset, parseErr := strconv.Atoi(offsetText)\n\t\tif parseErr != nil {\n\t\t\treturn ISO8601{}, fmt.Errorf(\"ISO8601: %w\", parseErr)\n\t\t}\n\n\t\t// E.g. offset of +0300 is returned as 10800 which is - (3 * 60 * 60).\n\t\tsecondsEastUTC := offset * 60 * 60\n\n\t\t// fmt.Printf(\"parsing %s with offset %s, secondsEastUTC: %d, using time layout: %s\\n\", s, offsetText, secondsEastUTC, ISO8601ZUTCOffsetLayoutWithMicroseconds)\n\t\tif loc, ok := fixedEastUTCLocations[secondsEastUTC]; ok { // Specific (fixed) zone.\n\t\t\tif strings.Contains(s, \".\") {\n\t\t\t\ttt, err = time.ParseInLocation(ISO8601ZUTCOffsetLayoutWithMicroseconds, s, loc)\n\t\t\t} else {\n\t\t\t\ttt, err = time.ParseInLocation(ISO8601ZUTCOffsetLayoutWithoutMicroseconds, s, loc)\n\t\t\t}","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/jsonx/iso8601.go#L114-L150","documentation":"ParseISO8601 throws \"ISO8601: invalid timezone format: <suffix>\" when the string has an offset-looking sign after position 18, but the offset substring is structurally unusable: parseSignedOffset returned an inconsistent/zero length (idx+1 > idx+length) or the string ends before a complete offset could exist (len(s) <= idx+length+1). The offending suffix (everything from the +/- sign onward) is included verbatim in the message.","triggerScenarios":"Calling ParseISO8601 (or UnmarshalJSON/Scan) with strings like \"2024-01-02T15:04:05+\" (bare sign), \"2024-01-02T15:04:05+2\" (truncated offset), \"2024-01-02T15:04:05xyz+03\" (offset truncated by a trailing char), or any input where the trailing +/- region is not a complete +hh / +hh:mm style offset.","commonSituations":"Truncated timestamps from log tailing or fixed-width column reads; JSON payloads cut off mid-string; query parameters or config values where the offset was accidentally stripped (e.g. shell splitting on '+'); spreadsheet/CSV exports that mangle '+' characters.","solutions":["Log/inspect the suffix printed in the error and re-emit the complete timestamp including the full offset (e.g. +03:00 not +).","If the timestamp should be UTC, replace the broken suffix with \"Z\" or \"+00:00\" before parsing.","Strip the incomplete offset entirely so the string matches the plain ISO8601Layout (\"2024-01-02T15:04:05\") when the offset is unknowable.","Pre-validate the trailing offset with a regexp such as [+-]\\d{2}(:\\d{2})?$ before calling ParseISO8601."],"exampleFix":"// before\nt, err := jsonx.ParseISO8601(\"2024-01-02T15:04:05+\") // ISO8601: invalid timezone format: +\n// after\nt, err := jsonx.ParseISO8601(\"2024-01-02T15:04:05+03:00\")","handlingStrategy":"validation","validationCode":"var completeOffsetRe = regexp.MustCompile(`[+-]\\d{2}(:\\d{2})?$`)\n\nfunc hasCompleteOffset(s string) bool {\n\ti := strings.LastIndexAny(s, \"+-\")\n\treturn i >= 0 && completeOffsetRe.MatchString(s[i:])\n}\n\n// usage\nif !hasCompleteOffset(raw) {\n\treturn fmt.Errorf(\"timestamp %q has truncated timezone offset\", raw)\n}","typeGuard":"func isTruncatedOffset(s string) bool {\n\ti := strings.LastIndexAny(s, \"+-\")\n\treturn i >= 0 && i == len(s)-1 || (i >= 0 && !regexp.MustCompile(`[+-]\\d{2}(:\\d{2})?$`).MatchString(s[i:]))\n}","tryCatchPattern":"t, err := jsonx.ParseISO8601(raw)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid timezone format\") {\n\t\t// recover: treat as UTC or re-fetch the full timestamp from source\n\t\treturn jsonx.ParseISO8601(strings.TrimRight(raw, \"+-\") + \"Z\")\n\t}\n\treturn err\n}","preventionTips":["Never truncate timestamps to fixed widths when reading logs or DB columns","Quote timestamp values in shells/configs to avoid '+' being interpreted","Validate trailing offset completeness before parsing","Standardize on one full format (e.g. RFC3339) at every API boundary"],"tags":["go","time-parsing","iso8601","timezone-offset"],"backgroundTag":"invalid-timezone-offset","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}