{"record":{"id":"b6fdff1947a15907","repo":"PaddlePaddle/PaddleOCR","slug":"failed-to-create-2d-rendering-context","errorCode":null,"errorMessage":"Failed to create 2D rendering context.","messagePattern":"Failed to create 2D rendering context\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"paddleocr-js/packages/core/src/viz/canvas-factory.ts","lineNumber":23,"sourceCode":"\ntype AnyCanvas = OffscreenCanvas | HTMLCanvasElement;\n\nexport function createCanvas(width: number, height: number): AnyCanvas {\n  if (typeof OffscreenCanvas !== \"undefined\") {\n    return new OffscreenCanvas(width, height);\n  }\n  const canvas = document.createElement(\"canvas\");\n  canvas.width = width;\n  canvas.height = height;\n  return canvas;\n}\n\nexport function getContext2D(\n  canvas: AnyCanvas\n): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D {\n  const ctx = canvas.getContext(\"2d\");\n  if (!ctx) {\n    throw new Error(\"Failed to create 2D rendering context.\");\n  }\n  return ctx;\n}\n\nexport function canvasToBlob(canvas: AnyCanvas, type: string, quality: number): Promise<Blob> {\n  if (canvas instanceof OffscreenCanvas) {\n    return canvas.convertToBlob({ type, quality });\n  }\n  return new Promise<Blob>((resolve, reject) => {\n    canvas.toBlob(\n      (blob) => {\n        if (blob) {\n          resolve(blob);\n        } else {\n          reject(new Error(\"canvas.toBlob() returned null.\"));\n        }\n      },\n      type,","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/paddleocr-js/packages/core/src/viz/canvas-factory.ts#L5-L41","documentation":"Thrown by getContext2D() in viz/canvas-factory when canvas.getContext(\"2d\") returns null for either an HTMLCanvasElement or OffscreenCanvas. Visualization APIs (drawing detection boxes, rendering results to canvas/blob) need this context. Null typically means too many live contexts, a conflicting context type already bound to the canvas, or a DOM-less environment.","triggerScenarios":"Calling a viz/render API on a canvas that already has a \"webgl\"/\"webgpu\" context bound; after the page exhausted its canvas context budget; in jsdom or SSR where 2D contexts are not implemented.","commonSituations":"Reusing a WebGL canvas for OCR overlay drawing; long sessions rendering many result canvases; unit tests of visualization code under jsdom without the 'canvas' polyfill.","solutions":["Use a fresh canvas (or one previously used with \"2d\") for visualization output instead of one holding a WebGL context","Free old canvases (zero out width/height, drop references) before creating new ones","Install the 'canvas' npm package for jsdom-based tests","Render fewer, larger canvases or reuse one overlay canvas across frames"],"exampleFix":"// before\nconst ctx = glCanvas.getContext(\"2d\"); // null: webgl already bound -> library throws\n\n// after\nconst overlay = document.createElement(\"canvas\"); // dedicated 2D canvas\noverlay.width = img.width; overlay.height = img.height;\nconst ctx = overlay.getContext(\"2d\");","handlingStrategy":"validation","validationCode":"function canvasAccepts2d(canvas: HTMLCanvasElement | OffscreenCanvas): boolean {\n  return canvas.getContext(\"2d\") !== null;\n}","typeGuard":null,"tryCatchPattern":"try {\n  const ctx = getContext2D(overlayCanvas);\n  drawResults(ctx, result);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"2D rendering context\")) {\n    const fresh = document.createElement(\"canvas\"); // retry with a clean canvas\n    drawResults(getContext2D(fresh), result);\n  } else throw e;\n}","preventionTips":["Never pass a canvas that already holds a webgl/webgpu context to viz APIs","Allocate a dedicated overlay canvas for OCR visualization","Free unused canvases in long sessions"],"tags":["canvas","viz","browser","memory"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}