openzipkin/zipkin · error · IllegalArgumentException
calls were empty
Error message
calls were empty
What it means
AggregateCall.newVoidCall(List<Call<Void>>) aggregates zero or more void calls and throws IllegalArgumentException('calls were empty') when the list is empty — an aggregate with nothing to wait on has no defined success value (its execute() would have to block on nothing or return a fabricated result). With exactly one call it returns that call directly; only 2+ calls are wrapped.
Source
Thrown at zipkin/src/main/java/zipkin2/internal/AggregateCall.java:27
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import zipkin2.Call;
import zipkin2.Callback;
/**
* A call that blocks on others to complete before invoking a callback or returning from {@link
* #execute()}. The first error will be returned upstream, later ones will be suppressed.
*
* @param <I> the type of returned from {@link Call#execute()}
* @param <O> the type representing the aggregate success value
*/
public abstract class AggregateCall<I, O> extends Call.Base<O> {
public static Call<Void> newVoidCall(List<Call<Void>> calls) {
if (calls.isEmpty()) throw new IllegalArgumentException("calls were empty");
if (calls.size() == 1) return calls.get(0);
return new AggregateVoidCall(calls);
}
static final class AggregateVoidCall extends AggregateCall<Void, Void> {
AggregateVoidCall(List<Call<Void>> calls) {
super(calls);
}
@Override protected Void newOutput() {
return null;
}
@Override protected void append(Void input, Void output) {
}
@Override public AggregateVoidCall clone() {
return new AggregateVoidCall(cloneCalls());View on GitHub (pinned to 878ce2a1fa)
Solutions
- Guard for the empty case before aggregating: return a no-op Call (e.g. Call.create(null)) instead of calling newVoidCall.
- Skip issuing the aggregate operation entirely when the batch is empty.
- Ensure upstream batching cannot deliver empty lists (reporters should not flush zero spans).
Example fix
// before return AggregateCall.newVoidCall(calls); // calls may be [] // after return calls.isEmpty() ? Call.create(null) : AggregateCall.newVoidCall(calls);
Defensive patterns
Strategy: validation
Validate before calling
Call<Void> aggregate = calls.isEmpty()
? Call.create(null)
: AggregateCall.newVoidCall(calls); Prevention
- Guard every fan-out aggregation for the empty-batch case.
- Make upstream batching skip empty flushes.
When it happens
Trigger: Building a storage-layer bulk operation (e.g. SpanStore accepts/aggregates) from a fan-out list that happens to be empty — say, zero client addresses to check or an empty consumer batch passed to a compound call.
Common situations: Custom zipkin-server storage backends or collectors that aggregate per-index calls (Elasticsearch/Cassandra-style fan-out) and hit empty batches during low traffic or after filtering removes all items.
Related errors
- input is not a list
- List<Span> implies at least traceId and id fields
- v1 format is not supported. For help, contact https://gitter
- concurrency < 1
- storage == null
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/b003f020ed5639b8.
Report an issue: GitHub.