{"record":{"id":"4603e5508545ba82","repo":"kataras/iris","slug":"invalid-offset-seconds-d-s","errorCode":null,"errorMessage":"invalid offset seconds: %d: %s","messagePattern":"invalid offset seconds: (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/jsonx/iso8601.go","lineNumber":258,"sourceCode":"\tif hours > 24 {\n\t\treturn time.Time{}, fmt.Errorf(\"invalid offset hours: %d: %s\", hours, offset)\n\t}\n\n\tminutes, err := strconv.Atoi(offsetParts[1])\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"error parsing offset minutes: %s: %w\", offset, err)\n\t}\n\tif minutes > 60 {\n\t\treturn time.Time{}, fmt.Errorf(\"invalid offset minutes: %d: %s\", minutes, offset)\n\t}\n\n\tseconds, err := strconv.Atoi(offsetParts[2])\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"error parsing offset seconds: %s: %w\", offset, err)\n\t}\n\n\tif seconds > 60 {\n\t\treturn time.Time{}, fmt.Errorf(\"invalid offset seconds: %d: %s\", seconds, offset)\n\t}\n\n\ttotalOffset := time.Duration(sign) * (time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second)\n\treturn t.Add(-totalOffset), nil\n}\n\n// UnmarshalJSON parses the \"b\" into ISO8601 time.\nfunc (t *ISO8601) UnmarshalJSON(b []byte) error {\n\tif len(b) == 0 {\n\t\treturn nil\n\t}\n\n\ts := strings.Trim(string(b), `\"`)\n\ttt, err := ParseISO8601(s)\n\tif err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/jsonx/iso8601.go#L240-L276","documentation":"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.","triggerScenarios":"ParseISO8601 on a timestamp with an offset like '+03:30:99' — seconds parse as an integer but exceed 60.","commonSituations":"Serializers concatenating fields incorrectly; corrupted or hand-built timestamps; fuzz/bad-input tests.","solutions":["Correct the offset so seconds are within 0–59 (e.g. '+03:30:00').","Check the producer for width/order bugs when composing the offset.","Validate offsets with a strict regex (^[+-]\\d{1,2}:[0-5]\\d:[0-5]\\d$) before parsing."],"exampleFix":"// before\nParseISO8601(\"2024-01-02T15:04:05+03:30:99\") // invalid offset seconds: 99\n// after\nParseISO8601(\"2024-01-02T15:04:05+03:30:00\")","handlingStrategy":"validation","validationCode":"var fullOffsetRe = regexp.MustCompile(`^[+-]\\d{1,2}:[0-5]\\d:[0-5]\\d$`)\nfunc hasValidFullOffset(ts string) bool {\n\ti := strings.LastIndexAny(ts, \"+-\")\n\treturn i >= 0 && fullOffsetRe.MatchString(ts[i:])\n}","typeGuard":null,"tryCatchPattern":"tt, err := jsonx.ParseISO8601(s)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid offset seconds\") {\n\t\treturn fmt.Errorf(\"timestamp %q has out-of-range offset seconds\", s)\n\t}\n\treturn err\n}","preventionTips":["Validate full offsets against ^[+-]HH:MM:SS with each field range-checked.","Treat 60 as a leap-second-only value; reject it in application data.","Prefer RFC3339 timestamps that never include offset seconds."],"tags":["time-parsing","iso8601","timezone-offset","range-check"],"backgroundTag":"invalid-timezone-offset-format","analyzedSha":"7bedaf55a0b64bbb2248a5845a2c60d81a30996a","analyzedAt":"2026-08-30T20:38:16.250Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}