PaddlePaddle/PaddleOCR · error · Error
Failed to create a 2D canvas context in the OCR worker.
Error message
Failed to create a 2D canvas context in the OCR worker.
What it means
Thrown inside the OCR worker when an OffscreenCanvas is successfully created but getContext("2d", { willReadFrequently: true }) returns null. This is rarer than the capability gate and indicates the canvas could not allocate a 2D context at all - typically resource exhaustion (too many live canvases/GPU memory) or a browser engine defect, since the worker already verified OffscreenCanvas exists.
Source
Thrown at paddleocr-js/packages/core/src/platform/worker.ts:22
*/
import type { OpenCv, Mat } from "@techstark/opencv-js";
import type { SourceMatResult } from "./browser";
import { ensureServedFromHttp } from "./browser";
export interface WorkerSourcePayload {
kind: "imageBitmap";
imageBitmap: ImageBitmap;
}
function imageBitmapToImageData(imageBitmap: ImageBitmap): ImageData {
if (typeof OffscreenCanvas !== "function") {
throw new Error("Worker mode requires OffscreenCanvas support in this browser.");
}
const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
const ctx = canvas.getContext("2d", { willReadFrequently: true });
if (!ctx) {
throw new Error("Failed to create a 2D canvas context in the OCR worker.");
}
ctx.drawImage(imageBitmap, 0, 0);
return ctx.getImageData(0, 0, imageBitmap.width, imageBitmap.height);
}
function imageDataToMat(cv: OpenCv, imageData: ImageData): Mat {
return cv.matFromArray(imageData.height, imageData.width, cv.CV_8UC4, imageData.data);
}
function isWorkerSourcePayload(source: unknown): source is WorkerSourcePayload {
if (typeof source !== "object" || source === null) return false;
const candidate = source as Record<string, unknown>;
return (
candidate["kind"] === "imageBitmap" &&
typeof ImageBitmap !== "undefined" &&
candidate["imageBitmap"] instanceof ImageBitmap
);
}View on GitHub (pinned to 2661c7c0ef)
Solutions
- Throttle concurrent OCR jobs in the worker so only a few OffscreenCanvas instances are live at once
- Reuse a single OffscreenCanvas resized per job instead of allocating per image
- Reduce input image resolution before OCR to lower canvas memory
- If persistent, fall back to main-thread OCR
Example fix
// before
// worker processes all jobs in parallel, each allocating OffscreenCanvas
await Promise.all(images.map(i => client.recognize(i))); // may exhaust contexts
// after
const CONCURRENCY = 2;
for (let i = 0; i < images.length; i += CONCURRENCY) {
await Promise.all(images.slice(i, i + CONCURRENCY).map(img => client.recognize(img)));
} Defensive patterns
Strategy: fallback
Validate before calling
// Hard to pre-validate; bound concurrent worker jobs instead const MAX_CONCURRENT = 2; // keep live OffscreenCanvas count low
Try / catch
try {
await workerClient.recognize(bitmap);
} catch (e) {
if (e instanceof Error && e.message.includes("OCR worker")) {
await workerClient.dispose();
return mainThreadOcr.recognize(bitmap); // fallback path
}
throw e;
} Prevention
- Throttle concurrent recognize() calls through the worker
- Feed downscaled images when device memory is low
- Monitor worker restarts and degrade to main thread after repeated failures
When it happens
Trigger: High-throughput worker OCR pipelines that allocate a new OffscreenCanvas per image without releasing prior ones; devices under severe memory pressure; browsers that disable 2D contexts in certain worker configurations.
Common situations: Batch-processing hundreds of images through the worker without throttling; low-memory mobile devices; automation environments with software rendering.
Related errors
- Failed to create a 2D canvas context.
- Worker mode requires OffscreenCanvas support in this browser
- Failed to create 2D rendering context.
- worker mode does not support a custom fetch implementation.
- worker must be a boolean or an options object.
AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14).
Data as JSON: /api/errors/7a1e25043dc36a9a.
Report an issue: GitHub.