phaserjs/phaser · error · Error
Link Shader failed:
Error message
Link Shader failed:
What it means
Thrown by WebGLProgramWrapper when both vertex and fragment shaders compiled successfully but gl.LINK_STATUS is still false. This means the shaders are individually valid but incompatible with each other (e.g. varying/in-out mismatch, missing attribute bindings, or unsupported feature combination). Both shader sources are console.logged before the throw.
Source
Thrown at src/renderer/webgl/wrappers/WebGLProgramWrapper.js:345
var fs = this._fragmentShader;
var failed = 'Shader failed:\n';
if (!gl.getProgramParameter(program, gl.LINK_STATUS))
{
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
{
console.log(this.vertexSource);
throw new Error('Vertex ' + failed + gl.getShaderInfoLog(vs));
}
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
{
console.log(this.fragmentSource);
throw new Error('Fragment ' + failed + gl.getShaderInfoLog(fs));
}
console.log(this.vertexSource, this.fragmentSource);
throw new Error('Link Shader failed:' + gl.getProgramInfoLog(program));
}
this._setupAttributesAndUniforms();
this.compileTimeMs = performance.now() - this._compileStartTime;
this.compiling = false;
},
/**
* Set up the attributes and uniforms for this program.
* This is called after the program is created or re-created.
*
* @method Phaser.Renderer.WebGL.Wrappers.WebGLProgramWrapper#_setupAttributesAndUniforms
* @private
* @since 4.0.0
*/
_setupAttributesAndUniforms: function ()
{View on GitHub (pinned to 41be1e462b)
Solutions
- Read gl.getProgramInfoLog output appended to the error; link errors usually name the mismatched varying.
- Ensure vertex 'out' declarations and fragment 'in' declarations match in name, type, and (for WebGL2) layout location.
- Use a consistent #version in both stages.
- Confirm shaderAdditions applied to one stage have a matching patch in the other where varyings cross the boundary.
- Compare the two console.logged sources side by side for the interface block.
Example fix
// before: vertex outputs vUv but fragment declares inTuv // vertex: out vec2 vUv; // fragment: in vec2 inTuv; // name mismatch -> link fails // after // fragment: in vec2 vUv;
Defensive patterns
Strategy: try-catch
Validate before calling
function interfacesMatch(vsOuts, fsIns) {
const v = new Set(vsOuts.map(o => o.name + ':' + o.type));
return fsIns.every(i => v.has(i.name + ':' + i.type));
} Try / catch
try { program.create(vs, fs); } catch (e) { if (/Link Shader failed/.test(e.message)) { console.error('Link error:', e.message); /* align varyings between stages */ } else throw e; } Prevention
- Keep vertex/fragment varying declarations in a shared GLSL chunk.
- Use the same #version in both stages.
- When patching one stage with shaderAdditions, patch the matching one too.
When it happens
Trigger: Vertex shader outputs (varying/out) that the fragment shader does not consume or declares with a different type; fragment shader inputs the vertex shader never writes; missing/inconsistent layout(location=...) bindings; exceeding varying limits; using transform-feedback-only varyings incorrectly.
Common situations: Mixing GLSL versions between the two shaders (vertex 1.0, fragment 3.0); editing one shader but not the other during development; renaming a varying in one file only; shaderAdditions that patch one stage but not the matching one.
Related errors
- Vertex Shader failed:
- Fragment Shader failed:
- BaseFilterShader: No fragment shader source provided and no
- BatchHandler must have a name
- BatchHandlerStrip: Vertex count exceeds maximum per batch (
AI-assisted analysis of phaserjs/phaser@41be1e462b (2026-08-13).
Data as JSON: /api/errors/4973fc276d4be4ed.
Report an issue: GitHub.