PaddlePaddle/PaddleOCR · error

PaddleOCR worker instance has been disposed.

Error message

PaddleOCR worker instance has been disposed.

What it means

WorkerBackedPaddleOCR tracks a disposed flag set by dispose(). Every public method calls ensureActive() first and throws this error after disposal, preventing use of a terminated worker whose transport client no longer has a live counterpart.

Source

Thrown at paddleocr-js/packages/core/src/pipelines/ocr/worker-backed.ts:43

  private options: OcrPipelineRunnerOptions;
  private lastInitializationSummary: InitializationSummary | null;
  private modelConfig: OcrModelConfig;
  private transportClient: WorkerTransportClient;
  private initPromise: Promise<InitializationSummary> | null;
  private disposed: boolean;

  constructor(options: OcrPipelineRunnerOptions, transportClient: WorkerTransportClient) {
    this.options = options;
    this.lastInitializationSummary = null;
    this.modelConfig = cloneDefaultOcrConfig();
    this.transportClient = transportClient;
    this.initPromise = null;
    this.disposed = false;
  }

  ensureActive(): void {
    if (this.disposed) {
      throw new Error("PaddleOCR worker instance has been disposed.");
    }
  }

  async initialize(): Promise<InitializationSummary> {
    this.ensureActive();
    if (this.lastInitializationSummary) {
      return this.lastInitializationSummary;
    }
    if (!this.initPromise) {
      const ortOpts = (this.options.ortOptions || {}) as Record<string, unknown>;
      if (ortOpts["wasmPaths"] === undefined && typeof __ORT_WASM_CDN_PREFIX__ === "string") {
        console.warn(
          "[PaddleOCR.js] Worker mode: ortOptions.wasmPaths is not set — falling back to CDN (%s). " +
            "For version consistency between main thread and worker, set ortOptions.wasmPaths " +
            "to the path where your bundler outputs the onnxruntime-web WASM files " +
            '(e.g. ortOptions: { wasmPaths: "/assets/" }).',
          __ORT_WASM_CDN_PREFIX__
        );

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Create a fresh instance via PaddleOCR.create() after disposing instead of reusing the old one.
  2. Serialize teardown: await outstanding predict() promises before calling dispose().
  3. For shared instances, reference-count users and dispose only when the count reaches zero.

Example fix

// before
await ocr.dispose();
const result = await ocr.predict(image); // throws

// after
await ocr.dispose();
const ocr2 = await PaddleOCR.create();
const result = await ocr2.predict(image);
Defensive patterns

Strategy: validation

Validate before calling

// Track your own lifecycle: never call predict() after dispose()
let disposed = false;
async function teardown() {
  disposed = true;
  await inFlight; // settle outstanding predictions
  await ocr.dispose();
}
if (!disposed) await ocr.predict(img);

Try / catch

try {
  await ocr.predict(image);
} catch (e) {
  if (e instanceof Error && e.message === 'PaddleOCR worker instance has been disposed.') {
    ocr = await PaddleOCR.create(opts); // recreate and optionally retry once
    return ocr.predict(image);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling predict(), initialize(), setRuntimeParams(), etc. on a WorkerBackedPaddleOCR instance after await instance.dispose(); also double-dispose followed by reuse, or a race where a queued call resolves after dispose().

Common situations: Cleaning up on component unmount / route change while an in-flight prediction continues; shared singleton disposed by one consumer while another still uses it; React StrictMode double effects disposing then reusing.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/4372db251887a5e6. Report an issue: GitHub.