{"record":{"id":"77b5099233aedb45","repo":"Billionmail/BillionMail","slug":"end-date-must-not-be-before-start-date","errorCode":null,"errorMessage":"end_date must not be before start_date","messagePattern":"end_date must not be before start_date","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/internal/controller/operation_log/operation_log_v1_get_output_log.go","lineNumber":120,"sourceCode":"\tfor i, j := 0, len(lines)-1; i < j; i, j = i+1, j-1 {\n\t\tlines[i], lines[j] = lines[j], lines[i]\n\t}\n}\n\nfunc getLogFilesInRange(ctx context.Context, start, end string) ([]string, error) {\n\tlogDir := public.AbsPath(\"../logs/core/out\")\n\tlayout := \"2006-01-02\"\n\n\tstartDate, err := time.Parse(layout, start)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid start_date: %v\", err)\n\t}\n\tendDate, err := time.Parse(layout, end)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid end_date: %v\", err)\n\t}\n\tif endDate.Before(startDate) {\n\t\treturn nil, fmt.Errorf(\"end_date must not be before start_date\")\n\t}\n\n\tvar files []string\n\n\tfor d := startDate; !d.After(endDate); d = d.AddDate(0, 0, 1) {\n\t\tfname := filepath.Join(logDir, d.Format(\"2006-01-02\")+\".log\")\n\t\tif _, err := os.Stat(fname); err == nil {\n\t\t\tfiles = append(files, fname)\n\t\t}\n\t}\n\n\tif len(files) == 0 {\n\t\treturn nil, fmt.Errorf(\"no log files found\")\n\t}\n\treturn files, nil\n}\n","sourceCodeStart":102,"sourceCodeEnd":137,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/operation_log/operation_log_v1_get_output_log.go#L102-L137","documentation":"getLogFilesInRange builds the list of operation-log .log files between start_date and end_date. Before scanning, it validates the parsed dates and rejects any range whose end precedes its start. This guards the day-iteration loop, which would otherwise produce zero files silently.","triggerScenarios":"Calling GetOutputLog with end_date earlier than start_date, e.g. start_date=2026-09-05&end_date=2026-09-01, or swapped/mistyped date strings that still parse via time.Parse.","commonSituations":"Frontend date-range pickers letting users select an inverted range; clients passing parameters in wrong order; timezone-related off-by-one where 'today' is computed differently on client and server; API consumers reusing a saved end date after the start date was updated.","solutions":["Correct the request so end_date is on or after start_date","Swap the parameters if they were accidentally reversed","Add client-side validation in the date picker to prevent submitting inverted ranges","If the intent was 'most recent logs', pass only end_date and let defaults apply, or set start_date earlier"],"exampleFix":"// before\nGET /api/v1/operation-log/output?start_date=2026-09-05&end_date=2026-09-01\n// after\nGET /api/v1/operation-log/output?start_date=2026-09-01&end_date=2026-09-05","handlingStrategy":"validation","validationCode":"const s = new Date(startDate), e = new Date(endDate);\nif (isNaN(s) || isNaN(e)) throw new Error('invalid date');\nif (e < s) throw new Error('end_date must not be before start_date');","typeGuard":"function isValidRange(start: string, end: string): boolean {\n  const s = new Date(start), e = new Date(end);\n  return !isNaN(s.getTime()) && !isNaN(e.getTime()) && e >= s;\n}","tryCatchPattern":"try {\n  const files = await api.getOutputLog({ start_date, end_date });\n} catch (err) {\n  if (String(err.message).includes('end_date must not be before start_date')) {\n    // swap or prompt user to fix the range\n  }\n}","preventionTips":["Use a date-range picker that enforces end >= start","Validate the range client-side before the API call","Store dates in a single canonical format/timezone"],"tags":["validation","date-range","operation-log"],"backgroundTag":"invalid-date-range","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}