Stirling-Tools/Stirling-PDF · error · Error
Could not get canvas context
Error message
Could not get canvas context
What it means
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.
Source
Thrown at frontend/editor/src/core/services/enhancedPDFProcessingService.ts:431
/**
* Render a page thumbnail with specified quality
*/
private async renderPageThumbnail(
page: any,
quality: "low" | "medium" | "high",
): Promise<string> {
const scales = { low: 0.2, medium: 0.5, high: 0.8 }; // Reduced low quality for page editor
const scale = scales[quality];
const viewport = page.getViewport({ scale, rotation: 0 });
const canvas = document.createElement("canvas");
canvas.width = viewport.width;
canvas.height = viewport.height;
const context = canvas.getContext("2d");
if (!context) {
throw new Error("Could not get canvas context");
}
await page.render({ canvasContext: context, viewport }).promise;
return canvas.toDataURL("image/jpeg", 0.8); // Use JPEG for better compression
}
/**
* Create a ProcessedFile object
*/
private createProcessedFile(
file: File,
pages: PDFPage[],
totalPages: number,
): ProcessedFile {
return {
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
pages,
totalPages,View on GitHub (pinned to 9ef20dcab8)
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.
Example fix
// before
const context = canvas.getContext("2d");
if (!context) {
throw new Error("Could not get canvas context");
}
// after
const context = canvas.getContext("2d");
if (!context) {
return PLACEHOLDER_JPEG_DATA_URL;
} Defensive patterns
Strategy: fallback
Validate before calling
// Concurrency-cap page-editor thumbnail renders const MAX = 4; // keep under the browser's live-context budget
Type guard
function has2d(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & { getContext(c:"2d"): CanvasRenderingContext2D } {
return canvas.getContext("2d") !== null;
} Try / catch
try {
const ctx = canvas.getContext("2d");
if (!ctx) return PLACEHOLDER_JPEG_DATA_URL;
await page.render({ canvasContext: ctx, viewport }).promise;
return canvas.toDataURL("image/jpeg", 0.8);
} catch {
return PLACEHOLDER_JPEG_DATA_URL;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Could not get canvas context
- Canvas 2D context unavailable
- Database not initialized
- File ${file.name} appears to be corrupted
- Failed to decode image
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/5d869fb94641d113.
Report an issue: GitHub.