jaegertracing/jaeger · error

start_time_max must be after start_time_min

Error message

start_time_max must be after start_time_min

What it means

search_traces' buildQuery parses start_time_min and start_time_max into minStartTime/maxStartTime. If max is set and falls before min, the range is empty and the query would never match anything, so buildQuery refuses it with "start_time_max must be after start_time_min". It is a caller-side range validation error, raised before storage is queried.

Source

Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/search_traces.go:142

	}

	minStartTime, err := parseTimeParam(startTimeMinInput)
	if err != nil {
		return querysvc.TraceQueryParams{}, fmt.Errorf("invalid start_time_min: %w", err)
	}

	var maxStartTime time.Time
	if input.StartTimeMax != "" {
		maxStartTime, err = parseTimeParam(input.StartTimeMax)
		if err != nil {
			return querysvc.TraceQueryParams{}, fmt.Errorf("invalid start_time_max: %w", err)
		}
	} else {
		maxStartTime = time.Now()
	}

	if !maxStartTime.IsZero() && maxStartTime.Before(minStartTime) {
		return querysvc.TraceQueryParams{}, errors.New("start_time_max must be after start_time_min")
	}

	var durationMin, durationMax time.Duration
	if input.DurationMin != "" {
		durationMin, err = time.ParseDuration(input.DurationMin)
		if err != nil {
			return querysvc.TraceQueryParams{}, fmt.Errorf("invalid duration_min: %w", err)
		}
	}
	if input.DurationMax != "" {
		durationMax, err = time.ParseDuration(input.DurationMax)
		if err != nil {
			return querysvc.TraceQueryParams{}, fmt.Errorf("invalid duration_max: %w", err)
		}
	}

	if durationMin > 0 && durationMax > 0 && durationMax < durationMin {
		return querysvc.TraceQueryParams{}, errors.New("duration_max must be greater than duration_min")

View on GitHub (pinned to 806f444784)

Solutions

  1. Swap or correct the start_time_min/start_time_max values so max is strictly after min.
  2. If times are relative, compute both from a single clock reading before formatting them.
  3. Ensure both timestamps are formatted in the same time zone / RFC3339 offset the tool expects.
  4. Validate ordering client-side before invoking the tool to get a clearer message tied to your own context.

Example fix

// before
input := types.SearchTracesInput{
    StartTimeMin: "2024-06-02T00:00:00Z",
    StartTimeMax: "2024-06-01T00:00:00Z", // inverted
}
// after
minT, _ := time.Parse(time.RFC3339, "2024-06-01T00:00:00Z")
maxT, _ := time.Parse(time.RFC3339, "2024-06-02T00:00:00Z")
if !maxT.After(minT) {
    minT, maxT = maxT, minT // or fix the caller
}
Defensive patterns

Strategy: validation

Validate before calling

minT, _ := time.Parse(time.RFC3339, input.StartTimeMin)
maxT, _ := time.Parse(time.RFC3339, input.StartTimeMax)
if !maxT.After(minT) {
    return fmt.Errorf("start_time_max (%s) must be after start_time_min (%s)", maxT, minT)
}

Try / catch

out, err := handler.Handle(ctx, in)
if err != nil {
    if strings.Contains(err.Error(), "start_time_max must be after") {
        // swap or clamp the range and retry once
        in.StartTimeMin, in.StartTimeMax = in.StartTimeMax, in.StartTimeMin
        return handler.Handle(ctx, in)
    }
    return err
}

Prevention

When it happens

Trigger: Calling the search_traces MCP tool with start_time_max earlier than start_time_min, e.g. swapping the two values, passing relative times whose ordering inverts across time zones, or computing the max from a clock that lags the min.

Common situations: Swapped min/max arguments in an MCP tool call; building the range from 'last N hours' logic applied to the wrong bound; a client serializing datetimes in different time zones so the parsed max precedes the parsed min.

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/67e88c6f2b9319d3. Report an issue: GitHub.