{"record":{"id":"efdf773f254bfe46","repo":"kataras/iris","slug":"iso8601-invalid-timezone-offset-length-s","errorCode":null,"errorMessage":"ISO8601: invalid timezone offset length: %s","messagePattern":"ISO8601: invalid timezone offset length: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/jsonx/iso8601.go","lineNumber":192,"sourceCode":"\t}\n\n\toffsetText := s[idx:]\n\tsecondsEastUTC, err := parseOffsetToSeconds(offsetText)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\n\tloc, ok := fixedEastUTCLocations[secondsEastUTC]\n\tif !ok {\n\t\tloc = time.FixedZone(\"\", secondsEastUTC)\n\t}\n\n\treturn time.ParseInLocation(ISO8601ZUTCOffsetLayoutWithoutMicroseconds, s, loc)\n}\n\nfunc parseOffsetToSeconds(offsetText string) (int, error) {\n\tif len(offsetText) < 6 {\n\t\treturn 0, fmt.Errorf(\"ISO8601: invalid timezone offset length: %s\", offsetText)\n\t}\n\n\tsign := offsetText[0]\n\tif sign != '-' && sign != '+' {\n\t\treturn 0, fmt.Errorf(\"ISO8601: invalid timezone offset sign: %c\", sign)\n\t}\n\n\thours, err := strconv.Atoi(offsetText[1:3])\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"ISO8601: %w\", err)\n\t}\n\n\tminutes, err := strconv.Atoi(offsetText[4:6])\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"ISO8601: %w\", err)\n\t}\n\n\tsecondsEastUTC := (hours*60 + minutes) * 60","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/jsonx/iso8601.go#L174-L210","documentation":"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.","triggerScenarios":"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-'.","commonSituations":"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'.","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."],"exampleFix":"// before\ntt, err := jsonx.ParseISO8601(\"2024-01-02T15:04:05+03\") // invalid timezone offset length: +03\n// after\ntt, err := jsonx.ParseISO8601(\"2024-01-02T15:04:05+03:00\") // ok","handlingStrategy":"validation","validationCode":"var offsetTailRe = regexp.MustCompile(`[+-]\\d{2}:\\d{2}$`)\nfunc hasValidOffsetTail(s string) bool { return offsetTailRe.MatchString(s) }\n// also handle compact form: if regexp `[+-]\\d{4}$` matches, insert a colon before parsing","typeGuard":"func offsetTailIsComplete(s string) bool {\n\ti := strings.LastIndexAny(s, \"+-\")\n\tif i == -1 || len(s)-i < 6 {\n\t\treturn false\n\t}\n\ttail := s[i:]\n\treturn tail[3] == ':'\n}","tryCatchPattern":"tt, err := jsonx.ParseISO8601(normalizeOffset(s))\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid timezone offset length\") {\n\t\treturn fmt.Errorf(\"timestamp %q: offset must be +HH:MM or -HH:MM\", s)\n\t}\n\treturn err\n}","preventionTips":["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"],"tags":["go","jsonx","iso8601","timezone-offset","malformed-input"],"backgroundTag":"invalid-iso8601-offset","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}