openzipkin/zipkin · error · IllegalArgumentException

minDuration <= 0

Error message

minDuration <= 0

What it means

Thrown by QueryRequest.Builder.build() when minDuration is set to zero or a negative value. minDuration filters traces by span duration in microseconds, and a non-positive duration is meaningless as a filter. Zipkin rejects it at build time rather than returning wrong results.

Source

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

      this.limit = limit;
      return this;
    }

    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. Pass a positive duration in microseconds, e.g. .minDuration(100000) for 100ms
  2. If minDuration is optional, leave it unset (null) instead of setting it to 0
  3. Audit unit conversions feeding the value (ms to micros is *1000, nanos to micros is /1000)

Example fix

// before
builder.minDuration(durationMs / 1000); // integer division may yield 0

// after
builder.minDuration(durationMs * 1000); // milliseconds -> microseconds
Defensive patterns

Strategy: validation

Validate before calling

// duration is in microseconds; must be positive if present
if (minDuration != null && minDuration <= 0) {
    throw new IllegalArgumentException("minDuration must be positive microseconds, got: " + minDuration);
}
QueryRequest.Builder b = QueryRequest.newBuilder().endTs(endTs).limit(10);
if (minDuration != null) b.minDuration(minDuration);

Try / catch

try {
    builder.minDuration(minDurationMicros);
} catch (IllegalArgumentException e) {
    // input bug, never retry: surface the message to the caller/API client
    throw new BadRequestException(e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling .minDuration(0L) or .minDuration(-5L) on the builder; converting a user-supplied duration in the wrong unit (e.g. passing 0 nanoseconds after integer division, or a value already divided to 0); passing a duration string that failed to parse and defaulted to 0.

Common situations: Unit confusion between milliseconds, microseconds, and nanoseconds leading to a computed 0; a 'min duration' UI field left blank and coerced to 0; copying example code that used 0 as a placeholder.

Related errors


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