openzipkin/zipkin · error · IllegalArgumentException

maxDuration < minDuration

Error message

maxDuration < minDuration

What it means

Thrown by QueryRequest.Builder.build() when both minDuration and maxDuration are set but maxDuration is smaller than minDuration. The pair defines a duration window in microseconds; an inverted window is logically empty, so Zipkin rejects it eagerly as a caller bug.

Source

Thrown at zipkin/src/main/java/zipkin2/storage/QueryRequest.java:256

    }

    public QueryRequest build() {
      // coerce service and span names to lowercase
      if (serviceName != null) serviceName = serviceName.toLowerCase(Locale.ROOT);
      if (remoteServiceName != null) remoteServiceName = remoteServiceName.toLowerCase(Locale.ROOT);
      if (spanName != null) spanName = spanName.toLowerCase(Locale.ROOT);

      if ("".equals(serviceName)) serviceName = null;
      if ("".equals(remoteServiceName)) remoteServiceName = null;
      if ("".equals(spanName) || "all".equals(spanName)) spanName = null;

      if (endTs <= 0) throw new IllegalArgumentException("endTs <= 0");
      if (limit <= 0) throw new IllegalArgumentException("limit <= 0");
      if (lookback <= 0) throw new IllegalArgumentException("lookback <= 0");
      if (minDuration != null) {
        if (minDuration <= 0) throw new IllegalArgumentException("minDuration <= 0");
        if (maxDuration != null && maxDuration < minDuration) {
          throw new IllegalArgumentException("maxDuration < minDuration");
        }
      } else if (maxDuration != null) {
        throw new IllegalArgumentException("maxDuration is only valid with minDuration");
      }

      return new QueryRequest(
        serviceName,
        remoteServiceName,
        spanName,
        annotationQuery,
        minDuration,
        maxDuration,
        endTs,
        lookback,
        limit
      );
    }

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Ensure maxDuration >= minDuration, both in microseconds, before calling build()
  2. If the intent is a window, compute max explicitly: maxDuration = minDuration + windowMicros
  3. Add a UI/service-side validation that rejects or swaps inverted min/max pairs before they reach the builder

Example fix

// before
builder.minDuration(maxDuration).maxDuration(minDuration); // swapped

// after
builder.minDuration(minDuration).maxDuration(maxDuration);
Defensive patterns

Strategy: validation

Validate before calling

if (minDuration != null && maxDuration != null && maxDuration < minDuration) {
    throw new IllegalArgumentException(
        "maxDuration (" + maxDuration + ") must be >= minDuration (" + minDuration + ")");
}
QueryRequest.Builder b = QueryRequest.newBuilder().endTs(endTs).limit(10)
    .minDuration(minDuration);
if (maxDuration != null) b.maxDuration(maxDuration);

Try / catch

try {
    builder.minDuration(min).maxDuration(max).build();
} catch (IllegalArgumentException e) {
    // logical input error: report to user, do not retry
    throw new BadRequestException(e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling .minDuration(50000).maxDuration(10000) on the builder; swapping the two values when wiring UI fields; computing maxDuration from a delta (e.g. minDuration + range) where the delta is negative or the subtraction underflows.

Common situations: Two form fields ('min'/'max duration') entered in the wrong order by a user and passed through unvalidated; refactoring that renames variables and accidentally swaps the arguments; off-by-unit bugs that shrink maxDuration below minDuration.

Related errors


AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14). Data as JSON: /api/errors/f5ae32ff694c0c63. Report an issue: GitHub.