{"record":{"id":"24f50d5cab1753ca","repo":"kataras/iris","slug":"invalid-offset-hours-d-s","errorCode":null,"errorMessage":"invalid offset hours: %d: %s","messagePattern":"invalid offset hours: (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"x/jsonx/iso8601.go","lineNumber":241,"sourceCode":"func adjustForUnconventionalOffset(t time.Time, offset string) (time.Time, error) {\n\tsign := 1\n\tif offset[0] == '-' {\n\t\tsign = -1\n\t}\n\toffset = offset[1:]\n\n\toffsetParts := strings.Split(offset, \":\")\n\tif len(offsetParts) != 3 {\n\t\treturn time.Time{}, fmt.Errorf(\"invalid offset format: %s\", offset)\n\t}\n\n\thours, err := strconv.Atoi(offsetParts[0])\n\tif err != nil {\n\t\treturn time.Time{}, fmt.Errorf(\"error parsing offset hours: %s: %w\", offset, err)\n\t}\n\n\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}","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/kataras/iris/blob/7bedaf55a0b64bbb2248a5845a2c60d81a30996a/x/jsonx/iso8601.go#L223-L259","documentation":"After parsing the hours of an unconventional '+HH:MM:SS' offset, adjustForUnconventionalOffset rejects hour values greater than 24, since a UTC offset hour component can never exceed 24. The parsed hours and the full offset string are included in the message.","triggerScenarios":"ParseISO8601 on a timestamp with an offset like '+30:00:00' or '+99:00:00' — digits parse fine but exceed the 24-hour bound.","commonSituations":"Malformed timestamps produced by buggy serializers (e.g. concatenating wrong fields); hand-built offset strings; tests with deliberately bogus offsets.","solutions":["Correct the offset so its hour component is within 0–24 (e.g. '+03:00:00').","Verify the producer is not swapping fields (e.g. putting a year or day value into the offset hours slot).","Validate offsets at ingestion with a regex like ^[+-](0?[0-9]|1[0-9]|2[0-4]):[0-5]?[0-9]:[0-5]?[0-9]$ before parsing."],"exampleFix":"// before\nParseISO8601(\"2024-01-02T15:04:05+30:00:00\") // invalid offset hours: 30\n// after\nParseISO8601(\"2024-01-02T15:04:05+03:00:00\")","handlingStrategy":"validation","validationCode":"func offsetHoursInRange(ts string) bool {\n\ti := strings.LastIndexAny(ts, \"+-\")\n\tif i < 0 { return false }\n\tparts := strings.Split(ts[i+1:], \":\")\n\tif len(parts) != 3 { return false }\n\th, err := strconv.Atoi(parts[0])\n\treturn err == nil && h >= 0 && h <= 24\n}","typeGuard":null,"tryCatchPattern":"tt, err := jsonx.ParseISO8601(s)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid offset hours\") {\n\t\treturn fmt.Errorf(\"timestamp %q has out-of-range UTC offset\", s)\n\t}\n\treturn err\n}","preventionTips":["Validate offsets are within ±24:00:00 before parsing.","Check serializers for field-order bugs when composing offsets.","Prefer standard offsets like Z or +03:00 that skip the unconventional path."],"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"}