openzipkin/zipkin · error · IllegalArgumentException

endTs <= 0

Error message

endTs <= 0

What it means

CassandraSpanStore.getDependencies throws IllegalArgumentException ('endTs <= 0') when a non-positive end timestamp is passed to the dependency-link query. endTs anchors the aggregation window (endTs - lookback .. endTs); zero or negative values mean an unset/misparsed timestamp, and the Cassandra dependencies query cannot bucket them, so it fails fast.

Source

Thrown at zipkin-storage/cassandra/src/main/java/zipkin2/storage/cassandra/CassandraSpanStore.java:292

  @Override public Call<List<String>> getServiceNames() {
    if (!searchEnabled) return Call.emptyList();
    return serviceNames.clone();
  }

  @Override public Call<List<String>> getRemoteServiceNames(String serviceName) {
    if (serviceName.isEmpty() || !searchEnabled || remoteServiceNames == null) {
      return Call.emptyList();
    }
    return remoteServiceNames.create(serviceName);
  }

  @Override public Call<List<String>> getSpanNames(String serviceName) {
    if (serviceName.isEmpty() || !searchEnabled) return Call.emptyList();
    return spanNames.create(serviceName);
  }

  @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");
    return dependencies.create(endTs, lookback);
  }

  static final class TimestampRange {
    long startMillis;
    UUID startUUID;
    long endMillis;
    UUID endUUID;
  }

  TimestampRange timestampRange(QueryRequest request, int indexTtl) {
    long oldestData = Math.max(System.currentTimeMillis() - indexTtl * 1000L, 0); // >= 1970
    TimestampRange result = new TimestampRange();
    result.startMillis = Math.max((request.endTs() - request.lookback()), oldestData);
    result.startUUID = Uuids.startOf(result.startMillis);
    result.endMillis = Math.max(request.endTs(), oldestData);
    result.endUUID = Uuids.endOf(result.endMillis);

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Pass endTs as epoch milliseconds greater than zero, e.g. System.currentTimeMillis()
  2. Default omitted endTs to now at the caller: endTs != 0 ? endTs : System.currentTimeMillis()
  3. Verify lookback is also positive (it is checked separately) and in millis

Example fix

// before
long endTs = 0; // 'unset'
Call<List<DependencyLink>> links = spanStore.getDependencies(endTs, 86400000L);

// after
long endTs = System.currentTimeMillis();
Call<List<DependencyLink>> links = spanStore.getDependencies(endTs, 86400000L);
Defensive patterns

Strategy: validation

Validate before calling

long endTs = (endTsParam > 0) ? endTsParam : System.currentTimeMillis();
long lookback = (lookbackParam > 0) ? lookbackParam : 86400000L;
if (endTs <= 0 || lookback <= 0) throw new IllegalArgumentException("endTs and lookback must be positive epoch millis");

Prevention

When it happens

Trigger: Calling storage.spanStore().getDependencies(0, 86400000) or getDependencies(-1, ...) directly, or from code that defaulted endTs to 0 because no explicit end time was provided.

Common situations: Passing seconds instead of milliseconds (looks positive but tiny, or 0 for 'now' in seconds at epoch), unit confusion between microseconds and millis, or copying the Zipkin query API's optional endTs parameter into storage without defaulting it to System.currentTimeMillis().

Related errors


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