siyuan-note/siyuan · error · Error

Canvas 2D is unavailable

Error message

Canvas 2D is unavailable

What it means

GraphCanvasRenderer constructor guard: canvas.getContext("2d") returned null, so no 2D rendering context could be created for the relation graph canvas. The browser denied the context (context lost, too many contexts, headless/software rendering unavailable), and the fallback canvas renderer cannot operate.

Solutions

  1. Free other canvas contexts in the page and retry creating the renderer
  2. Verify GPU/blacklist status in the browser (about:gpu or chrome://gpu)
  3. Switch to a browser/environment that supports Canvas 2D
Defensive patterns

Strategy: type-guard

When it happens

Trigger: Thrown at app/src/layout/dock/graph/canvasRenderer.ts:11 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/755f3ecfc28a5c4d. Report an issue: GitHub.

Appendix: source

Thrown at app/src/layout/dock/graph/canvasRenderer.ts:11

import {getGraphNodeColor, IGraphRenderer, IGraphRenderState} from "./renderer";
import {getGraphArrowGeometry, getGraphArrowLength, getGraphEdgeOpacity, MIN_GRAPH_EDGE_WIDTH} from "./core";

export class GraphCanvasRenderer implements IGraphRenderer {
    private readonly canvas: HTMLCanvasElement;
    private readonly context: CanvasRenderingContext2D;

    constructor(canvas: HTMLCanvasElement) {
        const context = canvas.getContext("2d");
        if (!context) {
            throw new Error("Canvas 2D is unavailable");
        }
        this.canvas = canvas;
        this.context = context;
    }

    public render(state: IGraphRenderState) {
        const width = Math.max(1, Math.round(state.width * state.devicePixelRatio));
        const height = Math.max(1, Math.round(state.height * state.devicePixelRatio));
        if (this.canvas.width !== width || this.canvas.height !== height) {
            this.canvas.width = width;
            this.canvas.height = height;
        }
        const context = this.context;
        context.setTransform(state.devicePixelRatio, 0, 0, state.devicePixelRatio, 0, 0);
        context.clearRect(0, 0, state.width, state.height);
        context.lineWidth = Math.max(MIN_GRAPH_EDGE_WIDTH, state.options.linkWidth * state.camera.scale);
        context.lineCap = "round";
        this.drawEdgeGroup(state, false, false);

View on GitHub (pinned to 8641553a1f)