Billionmail/BillionMail · warning
start time must be greater or equal to end time
Error message
start time must be greater or equal to end time
What it means
FailedList validates the requested time window and defaults EndTime to now when zero. If EndTime is earlier than StartTime, the query would return nonsense, so the handler rejects it with this error. Despite the wording, the requirement is end >= start.
Source
Thrown at core/internal/controller/overview/overview_v1_failed_list.go:22
"billionmail-core/internal/service/maillog_stat"
"billionmail-core/internal/service/public"
"context"
"fmt"
"github.com/gogf/gf/v2/util/gconv"
"time"
"billionmail-core/api/overview/v1"
)
func (c *ControllerV1) FailedList(ctx context.Context, req *v1.FailedListReq) (res *v1.FailedListRes, err error) {
res = &v1.FailedListRes{}
if req.EndTime == 0 {
req.EndTime = time.Now().Unix()
}
if req.EndTime < req.StartTime {
err = fmt.Errorf("start time must be greater or equal to end time")
return
}
overview := maillog_stat.NewOverview()
failedList := overview.FailedList(req.CampaignId, req.Domain, req.StartTime, req.EndTime)
err = gconv.Struct(failedList, &res.Data)
if err != nil {
err = fmt.Errorf("failed to convert overview data: %v", err)
return
}
res.SetSuccess(public.LangCtx(ctx, "Success"))
return
}
View on GitHub (pinned to fc36c76c05)
Solutions
- Ensure StartTime <= EndTime in Unix seconds before calling the API
- Convert timestamps to seconds (divide ms by 1000) if sending millisecond precision
- Check NTP/clock sync if times come from a skewed machine
- Swap the values if they were accidentally reversed
Example fix
// before req.StartTime = time.Now().Add(24 * time.Hour).Unix() req.EndTime = time.Now().Unix() // after req.EndTime = time.Now().Unix() req.StartTime = req.EndTime - 24*3600
Defensive patterns
Strategy: validation
Validate before calling
if (typeof startTime !== 'number' || typeof endTime !== 'number') throw new Error('timestamps must be Unix seconds');
if (startTime > endTime) throw new Error('start time must be <= end time'); Type guard
function isUnixSeconds(n: unknown): n is number {
return typeof n === 'number' && Number.isInteger(n) && n < 1e11; // excludes ms timestamps
} Try / catch
try {
const data = await api.failedList({ start_time: s, end_time: e });
} catch (err) {
if (String(err.message).includes('greater or equal to end time')) {
[s, e] = [Math.min(s, e), Math.max(s, e)]; // or fix units
}
} Prevention
- Always send Unix seconds, never milliseconds
- Clamp end_time to now and start_time = end_time - window
- Compute start before end in time-window helpers
When it happens
Trigger: Calling the failed-list API with StartTime greater than EndTime, e.g. start=now, end=yesterday; forgetting that EndTime defaults to now while passing a StartTime in the future (e.g. wrong unit — milliseconds instead of seconds); clock-skewed clients sending future start times.
Common situations: Client sends timestamps in milliseconds (13-digit) while server expects Unix seconds, making start appear far in the future; reversed arguments when constructing the request; dashboard 'last 24h' logic computing start after an end timestamp captured earlier.
Related errors
- start time must be greater or equal to end time
- required column 'email' not found
- You cannot create more than 5000 batches
- No log files found in the given date range
- invalid start_date: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/3ad2fac75c5b2150.
Report an issue: GitHub.