{"record":{"id":"0661adfb88023d35","repo":"DavidHDev/react-bits","slug":"failed-to-create-webgl-buffer","errorCode":null,"errorMessage":"Failed to create WebGL buffer.","messagePattern":"Failed to create WebGL buffer\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx","lineNumber":451,"sourceCode":"  return va;\n}\n\nfunction resizeCanvasToDisplaySize(canvas: HTMLCanvasElement): boolean {\n  const dpr = Math.min(2, window.devicePixelRatio || 1);\n  const displayWidth = Math.round(canvas.clientWidth * dpr);\n  const displayHeight = Math.round(canvas.clientHeight * dpr);\n  const needResize = canvas.width !== displayWidth || canvas.height !== displayHeight;\n  if (needResize) {\n    canvas.width = displayWidth;\n    canvas.height = displayHeight;\n  }\n  return needResize;\n}\n\nfunction makeBuffer(gl: WebGL2RenderingContext, sizeOrData: number | ArrayBufferView, usage: number): WebGLBuffer {\n  const buf = gl.createBuffer();\n  if (!buf) {\n    throw new Error('Failed to create WebGL buffer.');\n  }\n  gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n\n  if (typeof sizeOrData === 'number') {\n    gl.bufferData(gl.ARRAY_BUFFER, sizeOrData, usage);\n  } else {\n    gl.bufferData(gl.ARRAY_BUFFER, sizeOrData, usage);\n  }\n\n  gl.bindBuffer(gl.ARRAY_BUFFER, null);\n  return buf;\n}\n\nfunction createAndSetupTexture(\n  gl: WebGL2RenderingContext,\n  minFilter: number,\n  magFilter: number,\n  wrapS: number,","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/DavidHDev/react-bits/blob/c7109dccb42e06592d1d9bc50bc87204697240e2/src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx#L433-L469","documentation":"makeBuffer calls gl.createBuffer(); when the GL implementation returns null it throws. createBuffer returns null on context loss (the webglcontextlost event has invalidated the context) or when the implementation has exhausted its object pool. This is a resource/context-lifecycle failure, not a usage bug.","triggerScenarios":"gl.createBuffer() returns null at src/ts-default/Components/InfiniteMenu/InfiniteMenu.tsx:448 inside makeBuffer, which is called repeatedly during InfiniteMenu.init to allocate vertex/instance buffers. Triggered right after a context-loss event or when GL object limits are hit.","commonSituations":"Too many InfiniteMenu instances (or other WebGL components) on one page exceeding the browser's live GL object/context limits; GPU process crash mid-session; tab backgrounded and context lost then a resize triggers re-init; mobile GPUs with small object pools.","solutions":["Listen for 'webglcontextlost' on the canvas and stop/skip re-init until 'webglcontextrestored' fires.","Reduce the number of simultaneously mounted WebGL components / disc instances to stay under GL object limits.","Dispose buffers and call gl.deleteBuffer when the component unmounts to free the pool.","Retry allocation once after a short delay in case the loss was transient; surface a fallback UI if it persists."],"exampleFix":"// before\nconst buf = gl.createBuffer();\nif (!buf) throw new Error('Failed to create WebGL buffer.');\n\n// after\ncanvas.addEventListener('webglcontextlost', e => { e.preventDefault(); contextLost = true; }, false);\ncanvas.addEventListener('webglcontextrestored', () => { contextLost = false; reinit(); }, false);\nif (contextLost) return null; // skip allocation while context is lost\nconst buf = gl.createBuffer();\nif (!buf) throw new Error('Failed to create WebGL buffer.');","handlingStrategy":"try-catch","validationCode":"// check context health before allocating\nfunction contextHealthy(gl: WebGL2RenderingContext): boolean {\n  // a lost context returns this constant from anygetError\n  return gl.isContextLost && !gl.isContextLost();\n}","typeGuard":"function hasBufferPool(gl: WebGL2RenderingContext): boolean {\n  // createBuffer returns null on lost context / exhausted pool\n  const probe = gl.createBuffer();\n  if (probe) { gl.deleteBuffer(probe); return true; }\n  return false;\n}","tryCatchPattern":"canvas.addEventListener('webglcontextlost', (e) => e.preventDefault());\ncanvas.addEventListener('webglcontextrestored', reinit);\ntry {\n  return makeBuffer(gl, sizeOrData, usage);\n} catch (e) {\n  if (e instanceof Error && /WebGL buffer/.test(e.message)) {\n    return retryOnceAfterRestore();\n  }\n  throw e;\n}","preventionTips":["Handle webglcontextlost/webglcontextrestored and stop allocating while lost.","Delete buffers on unmount to avoid exhausting the GL object pool.","Limit concurrent WebGL components on a single page.","Retry allocation once after context restore before giving up."],"tags":["webgl2","gpu","buffer","context-loss","resource-limits","infinitemenu"],"backgroundTag":null,"analyzedSha":"c7109dccb42e06592d1d9bc50bc87204697240e2","analyzedAt":"2026-08-13T02:32:07.327Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}