{"record":{"id":"5ddc4ea1b9d638c4","repo":"perspective-dev/perspective","slug":"fragment-shader-compile-error-name-info","errorCode":null,"errorMessage":"Fragment shader compile error [${name}]: ${info}","messagePattern":"Fragment shader compile error \\[(.+?)\\]: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/viewer-charts/src/ts/webgl/shader-registry.ts","lineNumber":66,"sourceCode":"        const gl = this._gl;\n\n        const vert = gl.createShader(gl.VERTEX_SHADER)!;\n        gl.shaderSource(vert, vertSrc);\n        gl.compileShader(vert);\n        if (!gl.getShaderParameter(vert, gl.COMPILE_STATUS)) {\n            const info = gl.getShaderInfoLog(vert);\n            gl.deleteShader(vert);\n            throw new Error(`Vertex shader compile error [${name}]: ${info}`);\n        }\n\n        const frag = gl.createShader(gl.FRAGMENT_SHADER)!;\n        gl.shaderSource(frag, fragSrc);\n        gl.compileShader(frag);\n        if (!gl.getShaderParameter(frag, gl.COMPILE_STATUS)) {\n            const info = gl.getShaderInfoLog(frag);\n            gl.deleteShader(vert);\n            gl.deleteShader(frag);\n            throw new Error(`Fragment shader compile error [${name}]: ${info}`);\n        }\n\n        program = gl.createProgram()!;\n        gl.attachShader(program, vert);\n        gl.attachShader(program, frag);\n        gl.linkProgram(program);\n\n        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n            const info = gl.getProgramInfoLog(program);\n            gl.deleteProgram(program);\n            gl.deleteShader(vert);\n            gl.deleteShader(frag);\n            throw new Error(`Shader link error [${name}]: ${info}`);\n        }\n\n        // Shaders can be deleted after linking\n        gl.deleteShader(vert);\n        gl.deleteShader(frag);","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/perspective-dev/perspective/blob/11c8238c0c9c0b9e490b5a6a2dc277afad1e980a/packages/viewer-charts/src/ts/webgl/shader-registry.ts#L48-L84","documentation":"The WebGL shader registry compiles a fragment shader via gl.compileShader and checks COMPILE_STATUS. If the GLSL source fed to the fragment shader is invalid (syntax error, unsupported construct, bad uniform/varying declaration), getOrCreate throws this Error including the shader name and the driver's info log. It deletes the partially-created vert/frag shader objects before throwing so no GPU resources leak.","triggerScenarios":"Calling getOrCreate (directly or via precompile) with a fragment shader source that fails gl.getShaderParameter(frag, gl.COMPILE_STATUS), e.g. GLSL syntax errors, using an unsupported GLSL version directive, or referencing undeclared variables/texture units.","commonSituations":"Hand-edited shader templates with a typo; shaders built by string concatenation that produce invalid GLSL on some GPU/driver (works on desktop GL, fails on mobile ES); using WebGL2-only syntax (e.g. 'in'/'out', texture()) in a WebGL1 context; missing precision qualifiers for float types on mobile.","solutions":["Read the ${info} log in the message — the GLSL compiler reports the exact line and reason; fix the fragment shader source accordingly.","Verify the fragment shader's #version directive matches the context (WebGL1: GLSL ES 1.00 default, WebGL2: '#version 300 es' first line, no leading whitespace/newline).","Add required precision qualifiers (e.g. 'precision mediump float;') which are mandatory in fragment shaders on mobile GPUs.","Test on the failing device/driver — some constructs compile on desktop but fail on ANGLE/Adreno/Mali; keep a fallback shader path.","If shaders are templated/generated, log the fully-assembled fragSrc before compiling to spot concatenation mistakes."],"exampleFix":"// before\nconst fragSrc = `\n  varying vec3 color;\n  void main() { gl_FragColor = vec4(color, 1.0); }\n`;\n// after (add mandatory precision for mobile GLSL ES)\nconst fragSrc = `\n  precision mediump float;\n  varying vec3 color;\n  void main() { gl_FragColor = vec4(color, 1.0); }\n`;","handlingStrategy":"try-catch","validationCode":"function validateFragSrc(src: string): string | null {\n  if (!/main\\s*\\(/.test(src)) return \"missing main()\";\n  if (/#version 300 es/.test(src) && !src.trimStart().startsWith(\"#version\")) return \"#version must be first line\";\n  if (!/#version 300 es/.test(src) && !/precision\\s+(lowp|mediump|highp)\\s+float/.test(src)) return \"missing float precision qualifier\";\n  return null;\n}","typeGuard":"function isShaderCompiled(gl: WebGL2RenderingContext, shader: WebGLShader): boolean {\n  return gl.getShaderParameter(shader, gl.COMPILE_STATUS) === true;\n}","tryCatchPattern":"try {\n  const program = registry.getOrCreate(name, vertSrc, fragSrc);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Fragment shader compile error\")) {\n    console.error(`Bad fragment shader \"${name}\":`, e.message);\n    fallBackToFlatColorProgram();\n  } else throw e;\n}","preventionTips":["Always start fragment shaders with a precision qualifier for float.","Keep the #version directive on the very first line with no leading whitespace.","Lint/validate generated shader sources in unit tests with a headless GL context.","Test shaders on the lowest-target device (mobile GLES) before shipping.","Log the fully-assembled source when shaders are templated."],"tags":["webgl","shader-compile","glsl","gpu"],"backgroundTag":"shader-compile-error","analyzedSha":"11c8238c0c9c0b9e490b5a6a2dc277afad1e980a","analyzedAt":"2026-09-09T00:35:19.377Z","contentChangedAt":"2026-09-09T00:35:19.377Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}