mozilla/pdf.js · error · Error

Cannot use the same canvas during multiple render() operatio

Error message

Cannot use the same canvas during multiple render() operations. Use different canvas or ensure previous operations were cancelled or completed.

What it means

Thrown by InternalRenderTask.initializeGraphics when the canvas it is about to paint to is already in the static #canvasInUse WeakSet. PDF.js tracks active canvases to prevent two render() calls from racing on the same 2D context, which would corrupt the framebuffer. The guard is released only when the previous task completes, errors, or is cancelled.

Source

Thrown at src/display/api.js:3398

    this._dependencyTracker = params.dependencyTracker;
    this._imagesTracker = params.imagesTracker;
    this._operationsFilter = operationsFilter;
  }

  get completed() {
    return this.capability.promise.catch(function () {
      // Ignoring errors, since we only want to know when rendering is
      // no longer pending.
    });
  }

  initializeGraphics({ transparency = false, optionalContentConfig }) {
    if (this.cancelled) {
      return;
    }
    if (this._canvas) {
      if (InternalRenderTask.#canvasInUse.has(this._canvas)) {
        throw new Error(
          "Cannot use the same canvas during multiple render() operations. " +
            "Use different canvas or ensure previous operations were " +
            "cancelled or completed."
        );
      }
      InternalRenderTask.#canvasInUse.add(this._canvas);
    }

    if (this._pdfBug && globalThis.StepperManager?.enabled) {
      this.stepper = globalThis.StepperManager.create(this._pageIndex);
      this.stepper.init(this.operatorList);
      this.stepper.nextBreakPoint = this.stepper.getNextBreakPoint();
    }
    const {
      viewport,
      transform,
      background,
      dependencyTracker,

View on GitHub (pinned to 5903d58d58)

Solutions

  1. Track the in-flight renderTask and call renderTask.cancel() before starting a new render on the same canvas.
  2. Await the previous renderTask.promise (or its .catch) before issuing the next render().
  3. Render to distinct canvases when overlapping renders are genuinely needed.

Example fix

// before
page.render({ canvasContext, viewport });
page.render({ canvasContext, viewport: newViewport });

// after
if (this.task) {
  this.task.cancel();
  await this.task.promise.catch(() => {});
}
this.task = page.render({ canvasContext, viewport: newViewport });
Defensive patterns

Strategy: validation

Validate before calling

let currentTask = null;
async function renderSafe(page, params) {
  if (currentTask) {
    currentTask.cancel();
    await currentTask.promise.catch(() => {});
  }
  currentTask = page.render(params);
  return currentTask.promise;
}

Type guard

null

Try / catch

try {
  await page.render(params).promise;
} catch (e) {
  if (e.message.startsWith('Cannot use the same canvas')) {
    // cancel prior render and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling page.render({ canvasContext }) twice with the same canvas/context while the first task is still running; reusing a canvas for a second render without awaiting or cancelling the first; queueing a zoom render before the previous one settled.

Common situations: Re-rendering on viewport change without cancelling the prior task; React/Vue components that reuse a <canvas> ref across rapid prop updates; thumbnail and main viewer sharing a canvas pool.

Related errors


AI-assisted analysis of mozilla/pdf.js@5903d58d58 (2026-08-13). Data as JSON: /api/errors/84de101b9826dd6e. Report an issue: GitHub.