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

  1. Treat IOException with message 'Canceled' as a normal outcome: do not retry it, just stop the work that owned the Call.
  2. Avoid calling execute() on calls you may cancel; coordinate with a flag or Future so only one path acts on the Call.
  3. 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

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.