jaegertracing/jaeger · error
duration_max must be greater than duration_min
Error message
duration_max must be greater than duration_min
What it means
search_traces' buildQuery parses duration_min and duration_max with time.ParseDuration and rejects a query where both are set and duration_max is smaller than duration_min. Such a duration window is empty and can never match, so the error prevents a guaranteed-empty search. Like the time-range check, it fires before any storage call.
Source
Thrown at cmd/jaeger/internal/extension/jaegerquery/internal/mcptools/internal/handlers/search_traces.go:160
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")
}
const defaultSearchDepth = 10
searchDepth := input.SearchDepth
if searchDepth <= 0 {
searchDepth = defaultSearchDepth
}
if searchDepth > h.maxResults {
searchDepth = h.maxResults
}
attributes := pcommon.NewMap()
for key, value := range input.Attributes {
attributes.PutStr(key, value)
}
if input.WithErrors {
attributes.PutStr("error", "true")
}View on GitHub (pinned to 806f444784)
Solutions
- Swap the duration_min/duration_max values so max is greater than min.
- Double-check the Go duration units on both values (ms vs s vs m) — unit mistakes silently change magnitude.
- Parse both values with time.ParseDuration client-side and assert max > min before calling the tool.
Example fix
// before
types.SearchTracesInput{DurationMin: "2s", DurationMax: "500ms"} // inverted
// after
minD, _ := time.ParseDuration("500ms")
maxD, _ := time.ParseDuration("2s")
if minD >= maxD {
minD, maxD = maxD, minD
}
types.SearchTracesInput{DurationMin: minD.String(), DurationMax: maxD.String()} Defensive patterns
Strategy: validation
Validate before calling
minD, err := time.ParseDuration(input.DurationMin); if err != nil { return err }
maxD, err := time.ParseDuration(input.DurationMax); if err != nil { return err }
if maxD < minD {
return fmt.Errorf("duration_max (%s) must be >= duration_min (%s)", maxD, minD)
} Try / catch
out, err := handler.Handle(ctx, in)
if err != nil {
if strings.Contains(err.Error(), "duration_max must be greater") {
in.DurationMin, in.DurationMax = in.DurationMax, in.DurationMin
return handler.Handle(ctx, in)
}
return err
} Prevention
- Write duration bounds with explicit units always (500ms, 2s) — never bare numbers.
- Validate min<max for every duration window at the config/UI layer.
- When converting between units (ms<->s), parse-and-reformat via time.Duration instead of manual arithmetic.
When it happens
Trigger: Calling the search_traces MCP tool with duration_max < duration_min (e.g. duration_min="1s", duration_max="500ms"), or passing values in mismatched units so the parsed max ends up smaller ("2ms" vs "1s").
Common situations: Swapped min/max fields in the request; unit confusion where one value is milliseconds and the other seconds (Go durations require explicit units like 100ms, 2s); a dashboard passing user-supplied bounds without validating order.
Related errors
- trace_id is required
- start_time_max must be after start_time_min
- only one of basic auth (--es.username/--es.password), --es.t
- trace not found
- trace_id is required
AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01).
Data as JSON: /api/errors/392b816ed3473b0c.
Report an issue: GitHub.