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

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.

Source

Thrown at core/internal/controller/overview/overview_v1_overview.go:23

	"billionmail-core/internal/service/public"
	"context"
	"fmt"
	"time"

	"github.com/gogf/gf/v2/util/gconv"

	"billionmail-core/api/overview/v1"
)

func (c *ControllerV1) Overview(ctx context.Context, req *v1.OverviewReq) (res *v1.OverviewRes, err error) {
	res = &v1.OverviewRes{}

	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()
	overviewMap := overview.Overview(req.CampaignId, req.Domain, req.StartTime, req.EndTime)

	err = gconv.Struct(overviewMap, &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

  1. Ensure StartTime <= EndTime in Unix seconds
  2. Convert millisecond timestamps to seconds before sending
  3. Sync clocks (NTP) if timestamps come from the client machine
  4. Swap values if accidentally reversed

Example fix

// before
params: { start_time: Date.now(), end_time: Date.now() - 86400000 }
// after
const end = Math.floor(Date.now()/1000);
params: { start_time: end - 86400, end_time: end }
Defensive patterns

Strategy: validation

Validate before calling

const end = endTime || Math.floor(Date.now()/1000);
if (startTime > end) throw new Error('start_time must be <= end_time (Unix seconds)');

Type guard

function isUnixSeconds(n: unknown): n is number {
  return typeof n === 'number' && Number.isInteger(n) && n < 1e11;
}

Try / catch

try {
  const data = await api.overview({ 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)];
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/c74773e0861ea64c. Report an issue: GitHub.