{"record":{"id":"5d869fb94641d113","repo":"Stirling-Tools/Stirling-PDF","slug":"could-not-get-canvas-context-5d869f","errorCode":null,"errorMessage":"Could not get canvas context","messagePattern":"Could not get canvas context","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/editor/src/core/services/enhancedPDFProcessingService.ts","lineNumber":431,"sourceCode":"\n  /**\n   * Render a page thumbnail with specified quality\n   */\n  private async renderPageThumbnail(\n    page: any,\n    quality: \"low\" | \"medium\" | \"high\",\n  ): Promise<string> {\n    const scales = { low: 0.2, medium: 0.5, high: 0.8 }; // Reduced low quality for page editor\n    const scale = scales[quality];\n\n    const viewport = page.getViewport({ scale, rotation: 0 });\n    const canvas = document.createElement(\"canvas\");\n    canvas.width = viewport.width;\n    canvas.height = viewport.height;\n\n    const context = canvas.getContext(\"2d\");\n    if (!context) {\n      throw new Error(\"Could not get canvas context\");\n    }\n\n    await page.render({ canvasContext: context, viewport }).promise;\n    return canvas.toDataURL(\"image/jpeg\", 0.8); // Use JPEG for better compression\n  }\n\n  /**\n   * Create a ProcessedFile object\n   */\n  private createProcessedFile(\n    file: File,\n    pages: PDFPage[],\n    totalPages: number,\n  ): ProcessedFile {\n    return {\n      id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n      pages,\n      totalPages,","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/core/services/enhancedPDFProcessingService.ts#L413-L449","documentation":"Identical mechanism to error 20: `renderPageThumbnail` creates a fresh canvas and requests a 2D context; null triggers the throw. The only differences are the caller (page-editor thumbnail at low/med/high quality) and that it serialises to JPEG.","triggerScenarios":"Bulk page-editor thumbnail rendering across many pages; headless/no-compositor environments; Safari canvas-context exhaustion; memory pressure during editing of a large multi-page document.","commonSituations":"Opening the page editor on a large PDF triggers dozens of concurrent `renderPageThumbnail` calls; testing the editor under Playwright without GPU; Safari denying context allocation after heavy use.","solutions":["Reuse one canvas per quality tier and clear between renders rather than allocating per page.","Cap concurrent thumbnail renders with a queue and skip/defer low-priority pages.","Return a placeholder JPEG when the context is null so the page editor stays usable.","In tests, run with a software GL backend so contexts are allocatable."],"exampleFix":"// before\nconst context = canvas.getContext(\"2d\");\nif (!context) {\n  throw new Error(\"Could not get canvas context\");\n}\n\n// after\nconst context = canvas.getContext(\"2d\");\nif (!context) {\n  return PLACEHOLDER_JPEG_DATA_URL;\n}","handlingStrategy":"fallback","validationCode":"// Concurrency-cap page-editor thumbnail renders\nconst MAX = 4; // keep under the browser's live-context budget","typeGuard":"function has2d(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext(c:\"2d\"): CanvasRenderingContext2D } {\n  return canvas.getContext(\"2d\") !== null;\n}","tryCatchPattern":"try {\n  const ctx = canvas.getContext(\"2d\");\n  if (!ctx) return PLACEHOLDER_JPEG_DATA_URL;\n  await page.render({ canvasContext: ctx, viewport }).promise;\n  return canvas.toDataURL(\"image/jpeg\", 0.8);\n} catch {\n  return PLACEHOLDER_JPEG_DATA_URL;\n}","preventionTips":["Reuse a canvas per quality tier instead of allocating per page.","Cap concurrent thumbnail renders in the page editor.","Always degrade to a placeholder JPEG so the editor stays usable.","Use a software GL backend in automated tests."],"tags":["canvas","browser","rendering","pdfjs","thumbnails","page-editor"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}