sickn33/agentic-awesome-skills · error

Shader link failed: ${gl.getProgramInfoLog(program)}

Error message

Shader link failed: ${gl.getProgramInfoLog(program)}

What it means

createProgram attaches the compiled vertex and fragment shaders, calls gl.linkProgram, and throws when LINK_STATUS is false, embedding the program info log. Link failures occur even when both shaders compiled — usually mismatched varying names or precision between stages, or too many varyings for the GPU.

Source

Thrown at skills/liuguang-banlan-ui/assets/starter/shared/spectral-field.js:230

  function compileShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      const message = gl.getShaderInfoLog(shader);
      gl.deleteShader(shader);
      throw new Error(`Shader compilation failed: ${message}`);
    }
    return shader;
  }

  function createProgram(gl) {
    const program = gl.createProgram();
    gl.attachShader(program, compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER));
    gl.attachShader(program, compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER));
    gl.linkProgram(program);
    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
      throw new Error(`Shader link failed: ${gl.getProgramInfoLog(program)}`);
    }
    return program;
  }

  function uniform(gl, program, name) {
    return gl.getUniformLocation(program, name);
  }

  class SpectralField {
    constructor(canvas, config) {
      this.canvas = canvas;
      this.config = config;
      this.applyFallbackConfig(config);
      this.available = false;
      this.error = null;
      this.motionPreference = window.matchMedia("(prefers-reduced-motion: reduce)");
      this.motionEnabled = !this.motionPreference.matches;
      this.visible = !document.hidden;

View on GitHub (pinned to 58d857988f)

Solutions

  1. Read the info log — it typically names the missing/undeclared varying in one stage
  2. Make varying names and precision identical in both shader strings
  3. Keep varying count under ~8 vectors for broad mobile support
  4. Ensure the vertex shader writes gl_Position on every code path

Example fix

// before
// vertex:   varying vec2 vUv;
// fragment: varying vec2 v_uv;   // mismatch -> link error

// after
// vertex:   varying vec2 vUv;
// fragment: varying vec2 vUv;
Defensive patterns

Strategy: try-catch

Try / catch

try { program = createProgram(gl); }
catch (e) {
  if (/Shader link failed/.test(e.message)) { console.error(e.message); return useFallbackRenderer(canvas); }
  throw e;
}

Prevention

When it happens

Trigger: Renaming a varying in VERTEX_SHADER but not FRAGMENT_SHADER (or vice versa); different precision qualifiers on a shared varying; exceeding MAX_VARYING_VECTORS; a vertex shader path that skips writing gl_Position.

Common situations: Customizing the pass and editing only one of the two shader strings; porting a shader pair from another demo with different interface names; low-end mobile GPUs with small varying limits.

Related errors


AI-assisted analysis of sickn33/agentic-awesome-skills@58d857988f (2026-08-26). Data as JSON: /api/errors/c941ce75cca7658c. Report an issue: GitHub.