unoplatform/uno · critical · Exception

Program link failed: {infoLog}

Error message

Program link failed: {infoLog}

What it means

CreateProgram in PixelBuffersGlCanvasElement links the vertex+fragment shader pair and throws when gl.GetProgram(LinkStatus) != GL_TRUE. Link failure means the two shaders compiled but cannot form a valid program together — the failure is almost always an interface mismatch (varying names/types, attribute locations) or a program-level limit, not a syntax problem (those surface at compile time, error 84).

Source

Thrown at src/SamplesApp/SamplesApp.Samples/Windows_UI_Composition/PixelBuffersGlCanvasElement.cs:229

				2 => ((byte)0, (byte)255, x),
				3 => ((byte)0, x, (byte)255),
				4 => (x, (byte)0, (byte)255),
				_ => ((byte)255, (byte)0, x),
			};
		}

		private static uint CreateProgram(GL gl, string vertexSource, string fragmentSource)
		{
			var vs = CompileShader(gl, ShaderType.VertexShader, vertexSource);
			var fs = CompileShader(gl, ShaderType.FragmentShader, fragmentSource);
			var prog = gl.CreateProgram();
			gl.AttachShader(prog, vs);
			gl.AttachShader(prog, fs);
			gl.LinkProgram(prog);
			gl.GetProgram(prog, ProgramPropertyARB.LinkStatus, out int linkStatus);
			if (linkStatus != (int)GLEnum.True)
			{
				throw new Exception("Program link failed: " + gl.GetProgramInfoLog(prog));
			}
			gl.DetachShader(prog, vs);
			gl.DetachShader(prog, fs);
			gl.DeleteShader(vs);
			gl.DeleteShader(fs);
			return prog;
		}

		private static uint CompileShader(GL gl, ShaderType type, string source)
		{
			var sh = gl.CreateShader(type);
			gl.ShaderSource(sh, source);
			gl.CompileShader(sh);
			gl.GetShader(sh, ShaderParameterName.CompileStatus, out int status);
			if (status != (int)GLEnum.True)
			{
				throw new Exception($"{type} compile failed: " + gl.GetShaderInfoLog(sh));
			}

View on GitHub (pinned to 0418340488)

Solutions

  1. Read the appended info log — link errors are specific ('varying vUV declared but not written', 'too many vertex attributes', etc.) and pin down the offending interface.
  2. Confirm both shaders received the same versionDef ('#version 300 es' for GLES, '#version 330' for desktop) — a stage compiled under one profile cannot link with another profile.
  3. Verify the vertex shader's `out` declarations exactly match the fragment shader's `in` declarations in name, type, and (on desktop) layout location.
  4. Check attribute locations do not collide: layout(location=0) aPos and layout(location=1) aUV are distinct here, but a duplicate would link-fail.
  5. Query MAX_TEXTURE_IMAGE_UNITS and MAX_VERTEX_ATTRIBS at Init to confirm the program's resource usage fits the context.

Example fix

// before
if (linkStatus != (int)GLEnum.True)
    throw new Exception("Program link failed: " + gl.GetProgramInfoLog(prog));

// after — also surface whether each stage is currently bound/attached
if (linkStatus != (int)GLEnum.True)
{
    var log = gl.GetProgramInfoLog(prog);
    throw new Exception($"Program link failed (vs={vs}, fs={fs}): {log}");
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the two shaders' interfaces before linking by checking they share the same GLSL profile
if (!vertexSource.StartsWith(versionDef) || !fragmentSource.StartsWith(versionDef))
    throw new Exception("Stage GLSL profile mismatch — link will fail.");
// Optionally pre-link bind attribute locations to avoid collisions
gl.BindAttribLocation(prog, 0, "aPos");
gl.BindAttribLocation(prog, 1, "aUV");

Try / catch

try { _program = CreateProgram(gl, vsSrc, fsSrc); }
catch (Exception ex) when (ex.Message.Contains("Program link failed"))
{
    App.MainWindow?.LogError($"Link failed; info: {ex.Message}");
    _program = 0; // skip rendering this element
}

Prevention

When it happens

Trigger: After gl.AttachShader + gl.LinkProgram on the texture-display program (vertex: aPos/aUV -> vUV; fragment: sampler2D uTex, samples texture(uTex, vUV)). GetProgram(LinkStatus) returns non-True (line 226-229). The info log from GetProgramInfoLog(prog) is appended to the message.

Common situations: Vertex output `out vec2 vUV` does not match fragment `in vec2 vUV` (type/location mismatch); the sampler uniform count exceeds MAX_TEXTURE_IMAGE_UNITS on constrained contexts; varying qualifiers differ (flat vs smooth); GLSL ES vs desktop GL `#version` directive mismatch between the two shader stages; both shaders compiled fine individually but reference the same attribute location with different types.

Related errors


AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13). Data as JSON: /api/errors/58f140060aa71eef. Report an issue: GitHub.