{"record":{"id":"c74773e0861ea64c","repo":"Billionmail/BillionMail","slug":"start-time-must-be-greater-or-equal-to-end-time-c74773","errorCode":null,"errorMessage":"start time must be greater or equal to end time","messagePattern":"start time must be greater or equal to end time","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/internal/controller/overview/overview_v1_overview.go","lineNumber":23,"sourceCode":"\t\"billionmail-core/internal/service/public\"\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/gogf/gf/v2/util/gconv\"\n\n\t\"billionmail-core/api/overview/v1\"\n)\n\nfunc (c *ControllerV1) Overview(ctx context.Context, req *v1.OverviewReq) (res *v1.OverviewRes, err error) {\n\tres = &v1.OverviewRes{}\n\n\tif req.EndTime == 0 {\n\t\treq.EndTime = time.Now().Unix()\n\t}\n\n\tif req.EndTime < req.StartTime {\n\t\terr = fmt.Errorf(\"start time must be greater or equal to end time\")\n\t\treturn\n\t}\n\n\toverview := maillog_stat.NewOverview()\n\toverviewMap := overview.Overview(req.CampaignId, req.Domain, req.StartTime, req.EndTime)\n\n\terr = gconv.Struct(overviewMap, &res.Data)\n\n\tif err != nil {\n\t\terr = fmt.Errorf(\"failed to convert overview data: %v\", err)\n\t\treturn\n\t}\n\n\tres.SetSuccess(public.LangCtx(ctx, \"Success\"))\n\n\treturn\n}\n","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/controller/overview/overview_v1_overview.go#L5-L41","documentation":"Overview validates the requested time window and defaults EndTime to now when zero. If EndTime is earlier than StartTime the handler rejects the request with this error, since the statistics query assumes a valid forward-looking range.","triggerScenarios":"Calling the overview API with StartTime > EndTime; passing StartTime in milliseconds while server expects seconds (so start looks like the far future); relying on the EndTime=0 default while sending a future StartTime.","commonSituations":"Reversed parameters in a dashboard query builder; unit mismatch (13-digit ms timestamps); clock skew on client machines; copying query params from a tool where the order was different.","solutions":["Ensure StartTime <= EndTime in Unix seconds","Convert millisecond timestamps to seconds before sending","Sync clocks (NTP) if timestamps come from the client machine","Swap values if accidentally reversed"],"exampleFix":"// before\nparams: { start_time: Date.now(), end_time: Date.now() - 86400000 }\n// after\nconst end = Math.floor(Date.now()/1000);\nparams: { start_time: end - 86400, end_time: end }","handlingStrategy":"validation","validationCode":"const end = endTime || Math.floor(Date.now()/1000);\nif (startTime > end) throw new Error('start_time must be <= end_time (Unix seconds)');","typeGuard":"function isUnixSeconds(n: unknown): n is number {\n  return typeof n === 'number' && Number.isInteger(n) && n < 1e11;\n}","tryCatchPattern":"try {\n  const data = await api.overview({ start_time: s, end_time: e });\n} catch (err) {\n  if (String(err.message).includes('greater or equal to end time')) {\n    [s, e] = [Math.min(s, e), Math.max(s, e)];\n  }\n}","preventionTips":["Normalize all timestamps to Unix seconds before sending","Omit end_time to use the server's now-default","Enforce forward-only ranges in dashboard builders"],"tags":["validation","timestamp","overview"],"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"}