{"record":{"id":"b44e0d0fdb5554a2","repo":"PaddlePaddle/PaddleOCR","slug":"ocr-worker-is-not-initialized","errorCode":null,"errorMessage":"OCR worker is not initialized.","messagePattern":"OCR worker is not initialized\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"paddleocr-js/packages/core/src/pipelines/ocr/worker-entry.ts","lineNumber":31,"sourceCode":"  let ocr: OcrPipelineRunner | null = null;\n\n  async function handleInit(payload: Record<string, unknown>) {\n    await ocr?.dispose();\n    ocr = new OcrPipelineRunner({\n      ...(payload.options as OcrPipelineRunnerOptions),\n      ensureServedFromHttp,\n      sourceToMat: sourcePayloadToMat\n    });\n    const summary = await ocr.initialize();\n    return {\n      summary,\n      modelConfig: ocr.getModelConfig()\n    };\n  }\n\n  async function handlePredict(payload: Record<string, unknown>) {\n    if (!ocr) {\n      throw new Error(\"OCR worker is not initialized.\");\n    }\n    const sources = payload.sources;\n    return ocr.predict(sources, (payload.params || {}) as OcrRuntimeParamsInput);\n  }\n\n  async function handleDispose() {\n    await ocr?.dispose();\n    ocr = null;\n    return {};\n  }\n\n  return async function handleMessage(type: string, payload: Record<string, unknown>) {\n    switch (type) {\n      case \"init\":\n        return handleInit(payload);\n      case \"predict\":\n        return handlePredict(payload);\n      case \"dispose\":","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/paddleocr-js/packages/core/src/pipelines/ocr/worker-entry.ts#L13-L49","documentation":"Inside the OCR Web Worker, the message handler keeps a module-level `ocr` instance created by the 'init' message and cleared by 'dispose'. If a 'predict' message arrives while `ocr` is null — never initialized, or already disposed — handlePredict throws this error, which is serialized back to the main thread as a rejected RPC.","triggerScenarios":"Calling predict() on a WorkerBackedPaddleOCR before awaiting initialize(); calling predict() concurrently with dispose(); a transport-level race where the predict message is delivered after dispose.","commonSituations":"Fire-and-forget init (not awaiting the initialize()/create() promise); shared worker instance disposed by another part of the app mid-batch; retry logic that predicts after teardown.","solutions":["Always await the promise returned by PaddleOCR.create()/initialize() before calling predict().","Ensure dispose() is not called while predictions are in flight (await them first).","After disposal, create and initialize a new instance for further work."],"exampleFix":"// before\nconst ocr = await PaddleOCR.create();\nvoid ocr.initialize(); // not awaited\nawait ocr.predict(image); // may throw\n\n// after\nconst ocr = await PaddleOCR.create();\nawait ocr.initialize();\nawait ocr.predict(image);","handlingStrategy":"validation","validationCode":"// Always await initialization before predicting\nconst ocr = await PaddleOCR.create();\nawait ocr.initialize();\nconst result = await ocr.predict(image);","typeGuard":null,"tryCatchPattern":"try {\n  await ocr.predict(image);\n} catch (e) {\n  if (e instanceof Error && e.message === 'OCR worker is not initialized.') {\n    await ocr.initialize(); // or recreate the instance\n    return ocr.predict(image);\n  }\n  throw e;\n}","preventionTips":["Expose only an async getReadyOcr() helper in your app that memoizes the initialized instance.","Never fire-and-forget initialize(); every predict call site should be downstream of the init promise."],"tags":["lifecycle","worker","initialization","usage-error"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}