openzipkin/zipkin · error · IOException
Canceled
Error message
Canceled
What it means
Call.Base.execute throws IOException('Canceled') when you execute a Call after cancel() was called on it. Cancellation in Zipkin is cooperative: it sets a flag rather than interrupting work, so a later execute() checks isCanceled() and fails with an IOException (cancellation is treated as an I/O condition, matching the method's throws clause).
Source
Thrown at zipkin/src/main/java/zipkin2/Call.java:381
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;
}
if (isCanceled()) {
callback.onError(new IOException("Canceled"));
} else {
this.doEnqueue(callback);
}View on GitHub (pinned to 878ce2a1fa)
Solutions
- Treat IOException with message 'Canceled' as a normal outcome: do not retry it, just stop the work that owned the Call.
- Avoid calling execute() on calls you may cancel; coordinate with a flag or Future so only one path acts on the Call.
- For timeouts, prefer cancelling the whole operation (and discarding the Call) instead of cancelling then executing.
Example fix
// before
new Thread(() -> call.cancel()).start();
List<Span> spans = call.execute(); // may throw IOException("Canceled")
// after
if (!call.isCanceled()) {
try {
List<Span> spans = call.execute();
} catch (IOException e) {
if ("Canceled".equals(e.getMessage())) return; // cancelled elsewhere: stop quietly
throw e;
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if (!call.isCanceled()) { result = call.execute(); } Try / catch
try { return call.execute(); } catch (IOException e) { if ("Canceled".equals(e.getMessage())) return null; // cancelled elsewhere: not an error
throw e; } Prevention
- Only one component should own a Call: either the canceller or the executer
- Do not retry 'Canceled' IOExceptions; they are intentional stop signals
- Prefer cancelling the enclosing operation, not the raw Call, in timeout wrappers
When it happens
Trigger: Calling call.cancel() (e.g. from a timeout handler or another thread) and then call.execute(); also a race where cancel() wins between the executed-flag check and doExecute().
Common situations: Timeout wrappers that cancel a call but let the original execute() proceed; cleanup code that cancels all in-flight calls during shutdown while a worker still tries to execute one.
Related errors
AI-assisted analysis of openzipkin/zipkin@878ce2a1fa (2026-08-14).
Data as JSON: /api/errors/79a8dfd9e25cf315.
Report an issue: GitHub.