siyuan-note/siyuan · error · Error

Unable to allocate graph rendering resource

Error message

Unable to allocate graph rendering resource

What it means

requireValue() is the null-guard wrapper around WebGL resource allocators (createProgram, createShader, createVertexArray, createBuffer, getUniformLocation). Any of them returning null trips 'Unable to allocate graph rendering resource'. WebGL functions return null when the context is lost, when the implementation refuses allocation, or when a uniform name does not exist in the program.

Source

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

        const gl = this.gl;
        const shader = this.requireValue(gl.createShader(type));
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
            const message = gl.getShaderInfoLog(shader) || "Unable to compile graph shader";
            gl.deleteShader(shader);
            throw new Error(message);
        }
        return shader;
    }

    private getUniform(program: WebGLProgram, name: string) {
        return this.requireValue(this.gl.getUniformLocation(program, name));
    }

    private requireValue<T>(value: T | null): T {
        if (value === null) {
            throw new Error("Unable to allocate graph rendering resource");
        }
        return value;
    }
}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Add a webglcontextlost handler that sets a 'lost' flag and short-circuits requireValue so the renderer stops allocating.
  2. Cross-check each getUniform name against the actual uniform declarations in the linked program (optimizer strips unused ones).
  3. Tear down and recreate the renderer on webglcontextrestored, re-allocating all programs/buffers.
  4. Reduce the number of simultaneously live WebGL contexts (one graph dock at a time).

Example fix

// before
private getUniform(program: WebGLProgram, name: string) {
    return this.requireValue(this.gl.getUniformLocation(program, name));
}
// after (distinguish location-missing from real alloc failure)
private getUniform(program: WebGLProgram, name: string) {
    const loc = this.gl.getUniformLocation(program, name);
    if (!loc) throw new Error(`Uniform '${name}' not found in program (stripped by optimizer?)`);
    return loc;
}
Defensive patterns

Strategy: try-catch

Type guard

function isWebGLContextLost(gl: WebGL2RenderingContext): boolean {
    return gl.isContextLost();
}

Try / catch

canvas.addEventListener('webglcontextlost', (e) => { e.preventDefault(); renderer?.dispose(); });
try { renderer = new WebGLRenderer(canvas); }
catch (e) { showGraphFallback(); }

Prevention

When it happens

Trigger: The webgl2 context was lost (webglcontextlost event) but the renderer kept allocating; too many buffers/VAOs exhausted driver pools; getUniformLocation called for a uniform name that the GLSL optimizer stripped because it is unused.

Common situations: Tab backgrounded and the OS reclaimed the GPU context; user opened dozens of graph tabs exhausting the context pool; a uniform was renamed in GLSL but getUniform still queries the old name; driver crash mid-session.

Related errors


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