Comfy-Org/ComfyUI · error · RuntimeError
Program linking failed:\n{error}
Error message
Program linking failed:\n{error} What it means
Raised by _create_program() when glLinkProgram() leaves GL_LINK_STATUS false; the driver's linker log is embedded in the message. Compilation of both stages succeeded, but the vertex and fragment shaders do not fit together — the classic causes are a varying/out declared in one stage but missing or mismatched type in the other, or more active samplers/uniforms than the ES3 limit.
Source
Thrown at comfy_extras/nodes_glsl.py:381
fragment_shader = _compile_shader(fragment_source, gl.GL_FRAGMENT_SHADER)
except RuntimeError:
gl.glDeleteShader(vertex_shader)
raise
program = gl.glCreateProgram()
gl.glAttachShader(program, vertex_shader)
gl.glAttachShader(program, fragment_shader)
gl.glLinkProgram(program)
gl.glDeleteShader(vertex_shader)
gl.glDeleteShader(fragment_shader)
if not gl.glGetProgramiv(program, gl.GL_LINK_STATUS):
error = gl.glGetProgramInfoLog(program)
if isinstance(error, bytes):
error = error.decode(errors="replace")
gl.glDeleteProgram(program)
raise RuntimeError(f"Program linking failed:\n{error}")
return program
def _render_shader_batch(
fragment_code: str,
width: int,
height: int,
image_batches: list[list[np.ndarray]],
floats: list[float],
ints: list[int],
bools: list[bool] | None = None,
curves: list[np.ndarray] | None = None,
) -> list[list[np.ndarray]]:
"""
Render a fragment shader for multiple batches efficiently.
Compiles shader once, reuses framebuffer/textures across batches.View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Read the linker info log in the error — it states exactly which symbol failed to match.
- Keep the fragment shader's 'in' declarations identical (name + type) to the vertex stage's 'out' declarations.
- Count sampler uniforms and stay under the implementation limit (query GL_MAX_TEXTURE_IMAGE_UNITS; commonly 16).
- Simplify the shader to a minimal version and add pieces back until the failing construct is found.
Example fix
// before (vertex out: vec2 v_uv) // fragment: in vec2 uv; ... // name mismatch -> link error // after // fragment: in vec2 v_uv; ... // matches vertex out exactly
Defensive patterns
Strategy: try-catch
Validate before calling
# If your fragment shader declares inputs, verify they match the vertex stage outputs
custom_ins = set(re.findall(r"^\s*in\s+\w+\s+(\w+)", fragment_code, re.M))
expected = {"v_uv"} # names emitted by the node's fixed vertex shader (adjust per node)
assert custom_ins <= expected or custom_ins == expected, f"unmatched fragment inputs: {custom_ins - expected}" Try / catch
try:
out = run_glsl(fragment_code, ...)
except RuntimeError as e:
if "Program linking failed" in str(e):
# the log lists the mismatched symbol; fix 'in' names/types to match vertex 'out's
raise ValueError(f"Fragment inputs must match vertex outputs: {e}") from e
raise Prevention
- Never rename or remove the interpolated varyings the built-in vertex stage provides.
- Keep sampler count under GL_MAX_TEXTURE_IMAGE_UNITS (query it once).
- After editing a shader, run a tiny 8x8 render first to catch link errors cheaply.
When it happens
Trigger: Editing the fragment shader's inputs so they no longer match the fixed vertex shader's outputs (name, type, or qualifier mismatch); exceeding GL_MAX_TEXTURE_IMAGE_UNITS by sampling too many textures; declaring conflicting precision for the same interpolated variable.
Common situations: Customizing the fragment code of the GLSL node and renaming/removing the interpolated varyings the built-in vertex stage emits; heavy multi-texture shaders on mobile/software renderers with low sampler limits.
Related errors
- Shader compilation failed:\n{error}
- eglCreatePbufferSurface() failed
- eglCreateContext() failed
- eglMakeCurrent() failed
- eglMakeCurrent() failed (EGL error: 0x{err:04X})
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/11baef3c023a4a7b.
Report an issue: GitHub.