siyuan-note/siyuan · error · Error

WebGL2 is unavailable

Error message

WebGL2 is unavailable

What it means

WebGLRenderer constructor requests canvas.getContext('webgl2', {...}) and throws when it returns null. WebGL2 (GLSL ES 3.00) is required because the shaders use #version 300 es; without it the graph renderer cannot run.

Source

Thrown at app/src/layout/dock/graph/webglRenderer.ts:211

    private highlightLine = new Float32Array([0, 0, 0, 1]);
    private highlightPoint = new Float32Array([0, 0, 0, 1]);
    private nodeColors = new Float32Array();
    private nodeStates = new Float32Array();
    private positionVersion = -1;
    private selectionVersion = -1;
    private styleVersion = -1;

    constructor(canvas: HTMLCanvasElement) {
        const gl = canvas.getContext("webgl2", {
            alpha: true,
            antialias: true,
            depth: false,
            premultipliedAlpha: true,
            preserveDrawingBuffer: false,
            stencil: false,
        });
        if (!gl) {
            throw new Error("WebGL2 is unavailable");
        }
        this.canvas = canvas;
        this.gl = gl;
        this.nodeProgram = this.createProgram(NODE_VERTEX_SHADER, NODE_FRAGMENT_SHADER);
        this.edgeProgram = this.createProgram(EDGE_VERTEX_SHADER, EDGE_FRAGMENT_SHADER);
        this.arrowProgram = this.createProgram(ARROW_VERTEX_SHADER, ARROW_FRAGMENT_SHADER);
        this.nodeVao = this.requireValue(gl.createVertexArray());
        this.edgeVao = this.requireValue(gl.createVertexArray());
        this.arrowVao = this.requireValue(gl.createVertexArray());
        this.nodePositionBuffer = this.createBuffer();
        this.nodeSizeBuffer = this.createBuffer();
        this.nodeColorBuffer = this.createBuffer();
        this.nodeStateBuffer = this.createBuffer();
        this.edgeEndpointBuffer = this.createBuffer();
        this.edgeColorBuffer = this.createBuffer();
        this.edgeStateBuffer = this.createBuffer();
        this.arrowEndpointBuffer = this.createBuffer();
        this.arrowSizeBuffer = this.createBuffer();

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Enable hardware acceleration in the browser/Electron settings and update GPU drivers.
  2. Feature-detect webgl2 before constructing WebGLRenderer and show a 'Graph requires WebGL2' message instead of crashing.
  3. Listen for the 'webglcontextlost' event on the canvas and tear down the renderer; offer to reload.
  4. For headless/CI use, launch with --use-gl=swiftshader or a software WebGL2 implementation.

Example fix

// before
const gl = canvas.getContext('webgl2', opts);
if (!gl) throw new Error('WebGL2 is unavailable');
// after
const gl = canvas.getContext('webgl2', opts);
if (!gl) { showMessage('Graph view requires WebGL2. Enable hardware acceleration.'); return null; }
Defensive patterns

Strategy: type-guard

Validate before calling

function supportsWebGL2(): boolean {
    try { return !!document.createElement('canvas').getContext('webgl2'); }
    catch { return false; }
}

Type guard

function webgl2Supported(): boolean {
    try { return !!document.createElement('canvas').getContext('webgl2'); }
    catch { return false; }
}

Try / catch

try { return new WebGLRenderer(canvas); }
catch (e) { showMessage('Graph view requires WebGL2. Enable hardware acceleration.'); return null; }

Prevention

When it happens

Trigger: Opening the graph dock in a browser or webview that only supports WebGL1 (older Safari, some embedded WebViews), with hardware acceleration disabled, in a headless environment without GPU access, or after a previous webgl2 context was lost and not restored.

Common situations: User disabled GPU acceleration in Electron/Chrome; Linux without proper GPU drivers; VM / remote desktop without GPU passthrough; older mobile webviews that predate WebGL2; Tilt/Mac KVM environments.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/61c49d952df47870. Report an issue: GitHub.