openzipkin/zipkin · error · IllegalArgumentException

limit <= 0

Error message

limit <= 0

What it means

Thrown by QueryRequest.Builder.build() in zipkin2.storage when the configured limit is zero or negative. The limit controls how many traces the storage backend returns per query, and Zipkin requires at least one result. This is a fail-fast guard so invalid queries never reach a storage component.

Source

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

    /** Sets {@link QueryRequest#limit()} */
    public Builder limit(int limit) {
      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,

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Set a positive limit, e.g. .limit(10) (the conventional Zipkin default) before build()
  2. Validate/sanitize any externally supplied limit: limit = Math.max(1, requestedLimit)
  3. If the value comes from config, check the property name/spelling and its resolved value at startup

Example fix

// before
QueryRequest request = QueryRequest.newBuilder()
    .endTs(endTs)
    .limit(0) // throws "limit <= 0"
    .build();

// after
QueryRequest request = QueryRequest.newBuilder()
    .endTs(endTs)
    .limit(10)
    .build();
Defensive patterns

Strategy: validation

Validate before calling

// before building the request
if (requestedLimit == null || requestedLimit <= 0) {
    throw new IllegalArgumentException("limit must be a positive integer, got: " + requestedLimit);
}
QueryRequest request = QueryRequest.newBuilder().endTs(endTs).limit(requestedLimit).build();

Try / catch

try {
    return QueryRequest.newBuilder().endTs(endTs).limit(limit).build();
} catch (IllegalArgumentException e) {
    // treat as caller input error: log and rethrow as 400-style error, do not retry
    throw new BadRequestException("Invalid trace query: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling QueryRequest.newBuilder().limit(0) (or a negative value) followed by build(); programmatically computing limit from a page-size variable that evaluates to 0 (e.g. empty config, integer underflow); passing a client-supplied ?limit=0 through to the builder without validating it first.

Common situations: Reading limit from application config/properties where the key is missing and defaults to 0 or unparses to 0; UI pagination code that passes 0 for 'no limit'; porting older code that assumed the server would silently clamp the value.

Related errors


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