openzipkin/zipkin · error · IllegalStateException
Already Executed
Error message
Already Executed
What it means
Call.Base.execute throws IllegalStateException('Already Executed') when execute() is invoked more than once on the same Call. Zipkin Calls are one-shot, modeled after OkHttp's Request: a Call represents a single invocation, and repeated execution would double-report or race the underlying resource. The executed flag is set under synchronization so the check is thread-safe.
Source
Thrown at zipkin/src/main/java/zipkin2/Call.java:376
@Override public String toString() {
return "ErrorHandling{call=" + delegate + ", errorHandler=" + errorHandler + "}";
}
@Override public Call<V> clone() {
return new ErrorHandling<>(errorHandler, delegate.clone());
}
}
public static abstract class Base<V> extends Call<V> {
volatile boolean canceled;
boolean executed;
protected Base() {
}
@Override public final V execute() throws IOException {
synchronized (this) {
if (this.executed) throw new IllegalStateException("Already Executed");
this.executed = true;
}
if (isCanceled()) {
throw new IOException("Canceled");
} else {
return this.doExecute();
}
}
protected abstract V doExecute() throws IOException;
@Override public final void enqueue(Callback<V> callback) {
synchronized (this) {
if (this.executed) throw new IllegalStateException("Already Executed");
this.executed = true;
}
View on GitHub (pinned to 878ce2a1fa)
Solutions
- Create a fresh Call for each attempt: re-invoke storage.getTraces(...) (Calls are cheap factories).
- Use call.clone() if the implementation supports it to re-run an identical request.
- Audit code paths where execute() and enqueue() can both run on the same Call instance.
Example fix
// before Call<List<Span>> call = storage.getTraces(query); List<Span> first = call.execute(); List<Span> retry = call.execute(); // IllegalStateException // after List<List<Span>> first = storage.getTraces(query).execute(); List<List<Span>> retry = storage.getTraces(query).execute();
Defensive patterns
Strategy: validation
Validate before calling
// never reuse a Call: re-create it per attempt Call<List<List<Span>>> attempt = storage.getTraces(query); // fresh each time
Try / catch
try { call.execute(); } catch (IllegalStateException e) { if ("Already Executed".equals(e.getMessage())) { /* logic bug: re-create the Call instead */ } throw e; } Prevention
- Treat zipkin Call objects as single-use requests, like OkHttp
- Do not cache Call fields; cache the query and mint Calls on demand
- Never let execute() and enqueue() both run on one Call
When it happens
Trigger: Holding a Call object (e.g. from storage.getTraces(...)) and calling execute() twice, or calling execute() after enqueue() on the same instance — enqueue also flips the executed flag.
Common situations: Retry loops that re-run the same Call instead of creating a new one; caching Call objects; helpers that both enqueue and execute depending on a flag; sharing a Call between threads.
Related errors
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/18f6b257efdd2559.
Report an issue: GitHub.