{"record":{"id":"11baef3c023a4a7b","repo":"Comfy-Org/ComfyUI","slug":"program-linking-failed-n-error","errorCode":null,"errorMessage":"Program linking failed:\\n{error}","messagePattern":"Program linking failed:\\\\n(.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"comfy_extras/nodes_glsl.py","lineNumber":381,"sourceCode":"        fragment_shader = _compile_shader(fragment_source, gl.GL_FRAGMENT_SHADER)\n    except RuntimeError:\n        gl.glDeleteShader(vertex_shader)\n        raise\n\n    program = gl.glCreateProgram()\n    gl.glAttachShader(program, vertex_shader)\n    gl.glAttachShader(program, fragment_shader)\n    gl.glLinkProgram(program)\n\n    gl.glDeleteShader(vertex_shader)\n    gl.glDeleteShader(fragment_shader)\n\n    if not gl.glGetProgramiv(program, gl.GL_LINK_STATUS):\n        error = gl.glGetProgramInfoLog(program)\n        if isinstance(error, bytes):\n            error = error.decode(errors=\"replace\")\n        gl.glDeleteProgram(program)\n        raise RuntimeError(f\"Program linking failed:\\n{error}\")\n\n    return program\n\n\ndef _render_shader_batch(\n    fragment_code: str,\n    width: int,\n    height: int,\n    image_batches: list[list[np.ndarray]],\n    floats: list[float],\n    ints: list[int],\n    bools: list[bool] | None = None,\n    curves: list[np.ndarray] | None = None,\n) -> list[list[np.ndarray]]:\n    \"\"\"\n    Render a fragment shader for multiple batches efficiently.\n\n    Compiles shader once, reuses framebuffer/textures across batches.","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_extras/nodes_glsl.py#L363-L399","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (vertex out: vec2 v_uv)\n// fragment: in vec2 uv; ...   // name mismatch -> link error\n\n// after\n// fragment: in vec2 v_uv; ... // matches vertex out exactly","handlingStrategy":"try-catch","validationCode":"# If your fragment shader declares inputs, verify they match the vertex stage outputs\ncustom_ins = set(re.findall(r\"^\\s*in\\s+\\w+\\s+(\\w+)\", fragment_code, re.M))\nexpected = {\"v_uv\"}  # names emitted by the node's fixed vertex shader (adjust per node)\nassert custom_ins <= expected or custom_ins == expected, f\"unmatched fragment inputs: {custom_ins - expected}\"","typeGuard":null,"tryCatchPattern":"try:\n    out = run_glsl(fragment_code, ...)\nexcept RuntimeError as e:\n    if \"Program linking failed\" in str(e):\n        # the log lists the mismatched symbol; fix 'in' names/types to match vertex 'out's\n        raise ValueError(f\"Fragment inputs must match vertex outputs: {e}\") from e\n    raise","preventionTips":["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."],"tags":["glsl","shader","linking","opengl"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}