openzipkin/zipkin · error · IllegalArgumentException

endTs <= 0

Error message

endTs <= 0

What it means

Thrown by MySQLSpanStore.getDependencies when the endTs argument is zero or negative. endTs is expected to be an epoch-millisecond timestamp that anchors the dependency-link window. The store validates it up front because the SQL it generates (endTs * 1000 - lookback * 1000) would produce nonsense windows otherwise. A lookback <= 0 is validated the same way on the next line.

Source

Thrown at zipkin-storage/mysql-v1/src/main/java/zipkin2/storage/mysql/v1/MySQLSpanStore.java:106

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

  @Override public Call<List<String>> getRemoteServiceNames(String serviceName) {
    if (serviceName.isEmpty() || !searchEnabled || !schema.hasRemoteServiceName) {
      return Call.emptyList();
    }
    return dataSourceCallFactory.create(new SelectRemoteServiceNames(schema, serviceName));
  }

  @Override public Call<List<String>> getSpanNames(String serviceName) {
    if (serviceName.isEmpty() || !searchEnabled) return Call.emptyList();
    return dataSourceCallFactory.create(new SelectSpanNames(schema, 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");

    if (schema.hasPreAggregatedDependencies) {
      return dataSourceCallFactory.create(new SelectDependencies(schema, epochDays(endTs, lookback)));
    }
    return dataSourceCallFactory.create(
      new AggregateDependencies(schema, endTs * 1000 - lookback * 1000, endTs * 1000));
  }
}

View on GitHub (pinned to 878ce2a1fa)

Solutions

  1. Pass endTs as epoch milliseconds, e.g. System.currentTimeMillis(), and a positive lookback in millis.
  2. Validate both arguments at the call site before invoking getDependencies and substitute sane defaults (now, 1 day lookback) when they are unset.
  3. If wrapping the Zipkin query API in a service, reject requests with endTs <= 0 with a 400 response instead of letting the exception escape.

Example fix

// before
long endTs = 0; // never set
Call<List<DependencyLink>> call = storage.spanStore().getDependencies(endTs, lookback);

// after
long endTs = System.currentTimeMillis();
Call<List<DependencyLink>> call = storage.spanStore().getDependencies(endTs, lookback);
Defensive patterns

Strategy: validation

Validate before calling

long endTs = /* from request */;
if (endTs <= 0) endTs = System.currentTimeMillis();
if (lookback <= 0) lookback = 86_400_000L; // 1 day
Call<List<DependencyLink>> call = storage.spanStore().getDependencies(endTs, lookback);

Try / catch

try { storage.spanStore().getDependencies(endTs, lookback).execute(); } catch (IllegalArgumentException e) { /* map to 400 Bad Request for the caller */ }

Prevention

When it happens

Trigger: Calling MySQLStorage.spanStore().getDependencies(endTs, lookback) with endTs = 0, a negative number, or an uninitialized long. Typically happens when a caller passes seconds instead of millis of passes a default primitive long that was never set.

Common situations: Porting code from another storage backend that accepted 0 as 'now', passing System.currentTimeMillis()/1000 (seconds) where millis is expected, or copying the DependencyLink query from a UI that sends endTs as an optional parameter that defaults to 0.

Related errors


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