openzipkin/zipkin · error · IllegalArgumentException

endTs <= 0

Error message

endTs <= 0

What it means

ElasticsearchSpanStore.getDependencies(endTs, lookback) returns pre-computed dependency links for the window [endTs - lookback, endTs]. Both arguments must be positive epoch-milliseconds; endTs <= 0 is rejected immediately with IllegalArgumentException because a non-positive end timestamp defines no valid window and would format invalid index names.

Source

Thrown at zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchSpanStore.java:188

    long beginMillis = endMillis - namesLookback;

    List<String> indices = indexNameFormatter.formatTypeAndRange(TYPE_SPAN, beginMillis, endMillis);
    if (indices.isEmpty()) return Call.emptyList();

    // A span name is only valid on a local endpoint, as a span name is defined locally
    SearchRequest.Filters filters = new SearchRequest.Filters()
      .addRange("timestamp_millis", beginMillis, endMillis)
      .addTerm("localEndpoint.serviceName", serviceName.toLowerCase(Locale.ROOT));

    SearchRequest request = SearchRequest.create(indices).filters(filters)
      .addAggregation(Aggregation.terms(term, Integer.MAX_VALUE));

    return search.newCall(request, BodyConverters.KEYS);
  }

  @Override
  public Call<List<DependencyLink>> getDependencies(long endTs, long lookback) {
    if (endTs <= 0) throw new IllegalArgumentException("endTs <= 0");
    if (lookback <= 0) throw new IllegalArgumentException("lookback <= 0");

    long beginMillis = Math.max(endTs - lookback, EARLIEST_MS);

    // We just return all dependencies in the days that fall within endTs and lookback as
    // dependency links themselves don't have timestamps.
    List<String> indices =
      indexNameFormatter.formatTypeAndRange(TYPE_DEPENDENCY, beginMillis, endTs);
    if (indices.isEmpty()) return Call.emptyList();

    return search.newCall(SearchRequest.create(indices), BodyConverters.DEPENDENCY_LINKS);
  }

  static final class GetSpansByTraceId implements Call.FlatMapper<List<String>, List<Span>> {
    final SearchCallFactory search;
    final List<String> indices;

    GetSpansByTraceId(SearchCallFactory search, List<String> indices) {

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Pass a real epoch-millisecond end timestamp, e.g. System.currentTimeMillis().
  2. Audit the call site for unit bugs (seconds vs millis) and unset long fields.
  3. If endTs is optional in your API, substitute 'now' before calling getDependencies.

Example fix

// before
storage.spanStore().getDependencies(0, 86400000L); // IllegalArgumentException: endTs <= 0

// after
long endTs = request.endTs() > 0 ? request.endTs() : System.currentTimeMillis();
storage.spanStore().getDependencies(endTs, 86400000L);
Defensive patterns

Strategy: validation

Validate before calling

long endTs = (request.endTs() > 0) ? request.endTs() : System.currentTimeMillis();
long lookback = (request.lookback() > 0) ? request.lookback() : 86400000L;
if (endTs <= 0 || lookback <= 0) {
  throw new IllegalArgumentException("endTs and lookback must be positive epoch millis");
}
Call<List<DependencyLink>> links = storage.spanStore().getDependencies(endTs, lookback);

Type guard

static boolean isValidDependencyWindow(long endTs, long lookback) {
  return endTs > 0 && lookback > 0; // both must be positive epoch-millis
}

Prevention

When it happens

Trigger: Calling getDependencies(0, lookback), getDependencies(-1, ...), or passing seconds instead of epoch millis that underflow to <= 0; also passing an unset primitive long default (0L) from a config object or DTO that was never populated.

Common situations: Copy-paste code that assumes endTs defaults to 'now' (it does not — the caller must supply System.currentTimeMillis()); unit tests with dummy zeros; DTOs with primitive long fields left unset.

Related errors


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