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
- Pass endTs as epoch milliseconds greater than zero, e.g. System.currentTimeMillis()
- Default omitted endTs to now at the caller: endTs != 0 ? endTs : System.currentTimeMillis()
- 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
- Default optional endTs to System.currentTimeMillis() before calling storage
- Standardize on epoch millis across your tracing tooling to avoid unit confusion
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
- Start bucket ({startBucket}) > end bucket ({endBucket})
- maxConnections <= 0
- maxTraceCols <= 0
- indexFetchMultiplier <= 0
- %s contains an invalid IPv6 literal
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/9485e383e8d258d1.
Report an issue: GitHub.