cube-js/cube · error · Error

CancelToken was already canceled

Error message

CancelToken was already canceled

What it means

CancelToken.cancel() guards against double-cancellation: if the token's `canceled` flag is already true, calling cancel() again throws 'CancelToken was already canceled'. The token coordinates cancellation of deferred/queued CancelablePromises; canceling is a one-shot transition. Callers that issue cancel() more than once (e.g. from multiple event paths) hit this error.

Source

Thrown at packages/cubejs-backend-shared/src/promises.ts:61

      resolve();
    };
  });
  promise.cancel = cancel;

  return promise;
}

class CancelToken {
  protected readonly deferred: (() => Promise<void> | void)[] = [];

  protected readonly withQueue: CancelablePromiseCancel[] = [];

  protected canceled = false;

  public async cancel(): Promise<void> {
    if (this.canceled) {
      throw new Error('CancelToken was already canceled');
    }

    this.canceled = true;

    if (this.deferred.length) {
      await Promise.all(this.deferred.map(async (queued) => queued()));
    }

    if (this.withQueue.length) {
      await Promise.all(
        this.withQueue.map((cb) => cb())
      );
    }
  }

  public defer(fn: () => Promise<void> | void): void {
    this.deferred.push(fn);
  }

View on GitHub (pinned to 7d981676b3)

Solutions

  1. Check the token state before canceling, or track locally whether cancel was already issued on your side.
  2. Wrap cancel() in try/catch and treat the 'already canceled' error as a no-op success.
  3. Ensure a single owner/path is responsible for canceling a given token.
  4. Serialize cancellation logic (idempotent wrapper storing a promise of the first cancel).

Example fix

// before
await token.cancel();
await token.cancel(); // throws
// after
try { await token.cancel(); } catch (e) { /* already canceled: ignore */ }
Defensive patterns

Strategy: try-catch

Validate before calling

// track cancellation state on your side before calling
if (!alreadyCanceled) {
  await token.cancel();
  alreadyCanceled = true;
}

Type guard

const isAlreadyCanceled = (e: unknown): boolean =>
  e instanceof Error && e.message === 'CancelToken was already canceled';

Try / catch

try {
  await token.cancel();
} catch (e) {
  if (!isAlreadyCanceled(e)) throw e; // double-cancel is treated as success
}

Prevention

When it happens

Trigger: Calling token.cancel() twice — e.g. once from a request-abort handler and again on shutdown/timeout cleanup; or racing cancel() invocations that are not synchronized (the flag check is not atomic against concurrent async callers).

Common situations: Component unmount triggers cancel while a global timeout also cancels the same token; query orchestrator restart cancels tokens already canceled; duplicate event listeners each calling cancel().

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/d03358a86f678bbc. Report an issue: GitHub.