siyuan-note/siyuan · error · Error
Unable to create a canvas context for the PDF rectangle anno
Error message
Unable to create a canvas context for the PDF rectangle annotation
What it means
This error is thrown in app/src/asset/anno.ts when rendering a PDF page region onto a newly created canvas for a rectangle (rect) annotation screenshot. `canvas.getContext("2d")` returned null, so there is no 2D drawing context to pass to pdf.js's `page.render({canvasContext})`. A null context means the browser refused or failed to allocate a rendering context for the canvas element.
Source
Thrown at app/src/asset/anno.ts:1114
if (captureScale <= 0) {
throw new Error("PDF rectangle annotation has invalid coordinates");
}
const viewport = pdfPage.getViewport({scale: captureScale, rotation: totalRotation});
const captureBounds = getCaptureCanvasBounds(viewport.convertToViewportRectangle(position));
const captureViewport = pdfPage.getViewport({
scale: captureScale,
rotation: totalRotation,
offsetX: -captureBounds.left,
offsetY: -captureBounds.top,
});
const captureCanvas = document.createElement("canvas");
captureCanvas.width = captureBounds.width;
captureCanvas.height = captureBounds.height;
const captureCtx = captureCanvas.getContext("2d");
if (!captureCtx) {
throw new Error("Unable to create a canvas context for the PDF rectangle annotation");
}
await pdfPage.render({
canvasContext: captureCtx,
viewport: captureViewport,
}).promise;
const displayViewport = pdfPage.getViewport({scale: PDF_RECT_DISPLAY_SCALE, rotation: totalRotation});
const displayWidth = Math.min(
getCaptureDisplayWidth(displayViewport.convertToViewportRectangle(position)),
captureBounds.width,
);
const blob = await new Promise<Blob>((resolve, reject) => {
captureCanvas.toBlob((result) => {
if (result) {
resolve(result);
} else {
reject(new Error("Unable to encode the PDF rectangle annotation"));
}View on GitHub (pinned to 8641553a1f)
Solutions
- Reduce captureBounds.width/height (cap by device pixel ratio / zoom) before creating the canvas so it stays within browser limits
- Check the browser/environment: iOS Safari and WKWebView have strict canvas memory limits; retry with a smaller canvas or lower scale factor
- Verify the canvas is not detached/tainted and that hardware acceleration or GPU processes are not disabled in the runtime (Electron flags, --disable-gpu)
- Wrap the getContext call and fall back to re-creating a smaller canvas once before surfacing the error
Example fix
// before
const captureCanvas = document.createElement("canvas");
captureCanvas.width = captureBounds.width;
captureCanvas.height = captureBounds.height;
const captureCtx = captureCanvas.getContext("2d");
if (!captureCtx) {
throw new Error("Unable to create a canvas context for the PDF rectangle annotation");
}
// after
const MAX_AREA = 16777216; // 4096x4096, safe on iOS
const scale = Math.min(1, MAX_AREA / (captureBounds.width * captureBounds.height));
const captureCanvas = document.createElement("canvas");
captureCanvas.width = Math.floor(captureBounds.width * scale);
captureCanvas.height = Math.floor(captureBounds.height * scale);
const captureCtx = captureCanvas.getContext("2d");
if (!captureCtx) {
throw new Error("Unable to create a canvas context for the PDF rectangle annotation");
} Defensive patterns
Strategy: fallback
Validate before calling
const MAX_AREA = 16777216;
if (captureBounds.width * captureBounds.height > MAX_AREA) {
// scale down bounds before creating the canvas
} Type guard
function has2DContext(canvas: HTMLCanvasElement): canvas is HTMLCanvasElement & {getContext: (t: "2d") => CanvasRenderingContext2D} {
return !!canvas.getContext("2d");
} Try / catch
try {
await renderRectAnnotationCapture(page, bounds);
} catch (e) {
if (e.message.includes("canvas context")) {
// retry once with a halved-scale canvas, else show a user-facing hint
}
} Prevention
- Cap canvas dimensions by device pixel ratio and zoom before rendering
- Test PDF annotation export on iOS/Safari where canvas memory limits are strictest
- Detect getContext returning null early and degrade to a smaller-scale capture instead of throwing
When it happens
Trigger: Calling the rectangle-annotation screenshot/export path in app/src/asset/anno.ts:1114 when `captureCanvas.getContext("2d")` returns null right after a canvas is created with captureBounds dimensions and before `pdfPage.render(...)` is awaited.
Common situations: Very large captureBounds producing a canvas exceeding the browser's max canvas area (e.g. zoomed/high-DPI PDF pages on mobile Safari or iOS WKWebView, where total canvas memory is capped); the page running in an environment with canvas disabled or GPU process crash; memory pressure on embedded webviews preventing context allocation.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unable to load English commands: ${response.status}
- Failed to save agent session
- Failed to remove agent session
- Failed to update agent session permission
- View state value is too large
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/c0b01b8f1081f8b4.
Report an issue: GitHub.