{"record":{"id":"aa91de9d0f50614b","repo":"unoplatform/uno","slug":"the-framebuffer-readback-failed-with-readbackerro","errorCode":null,"errorMessage":"The framebuffer readback failed with {readbackError} while copying the framebuffer to the back buffer.","messagePattern":"The framebuffer readback failed with (.+?) while copying the framebuffer to the back buffer\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/AddIns/Uno.WinUI.Graphics3DGL/GLCanvasElement.cs","lineNumber":558,"sourceCode":"\t\t\t\tif (_readbackAsRgbaWithSwap)\n\t\t\t\t{\n\t\t\t\t\t_gl.ReadPixels(0, 0, (uint)RenderSize.Width, (uint)RenderSize.Height, GLEnum.Rgba, GLEnum.UnsignedByte, (void*)ptr);\n\t\t\t\t\tSwapRedBlue((byte*)ptr, (int)RenderSize.Width * (int)RenderSize.Height);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_gl.ReadPixels(0, 0, (uint)RenderSize.Width, (uint)RenderSize.Height, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);\n\t\t\t\t}\n\t\t\t});\n\t\t\t_backBuffer.PixelBuffer.Length = (uint)RenderSize.Width * (uint)RenderSize.Height * BytesPerPixel;\n#endif\n\n\t\t\t// glReadPixels doesn't throw on failure (e.g. an unsupported readback format); it only\n\t\t\t// sets a GL error and leaves the destination buffer untouched, which would show up as\n\t\t\t// a permanently blank canvas.\n\t\t\tif (_gl.GetError() is var readbackError && readbackError is not GLEnum.NoError)\n\t\t\t{\n\t\t\t\tthrow new InvalidOperationException(\n\t\t\t\t\t$\"The framebuffer readback failed with {readbackError} while copying the framebuffer to the back buffer.\");\n\t\t\t}\n\n\t\t\t_backBuffer.Invalidate();\n\t\t}\n\t\tcatch (Exception e)\n\t\t{\n\t\t\tif (this.Log().IsEnabled(LogLevel.Error))\n\t\t\t{\n\t\t\t\tthis.Log().Error($\"{nameof(GLCanvasElement)} rendering failed. The element will no longer render.\", e);\n\t\t\t}\n\n\t\t\tIsGLInitialized = false;\n\t\t}\n\t}\n\n\t// Decides the readback format once, while the context is current and the element's framebuffer\n\t// is bound (see OnLoaded). Any GLES context can lack BGRA read support, and extension strings","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/unoplatform/uno/blob/04183404888ea21b4e5bfa3493e8d5f15e972c3a/src/AddIns/Uno.WinUI.Graphics3DGL/GLCanvasElement.cs#L540-L576","documentation":"After glReadPixels copies the offscreen framebuffer into the back buffer, GLCanvasElement checks _gl.GetError(); any non-NoError code throws InvalidOperationException with the offending GL enum. glReadPixels itself does not throw — it silently sets a GL error and leaves the destination blank, so this explicit check converts a silent blank-canvas failure into a loud one. Common readback errors: GL_INVALID_OPERATION (no framebuffer bound / read buffer mismatch), GL_INVALID_ENUM (BGRA+UnsignedByte unsupported by the driver), GL_INVALID_VALUE.","triggerScenarios":"The driver rejects the glReadPixels format/type pair (BGRA + UnsignedByte), the read framebuffer is not complete at readback time, or no read framebuffer is bound — and ReadPixels sets GL_INVALID_ENUM/OPERATION.","commonSituations":"Running on a GL ES or older desktop GL driver without GL_BGRA pixel support; framebuffer invalidated between [49]'s check and readback; context made not-current on the render thread.","solutions":["Confirm the driver supports GL_BGRA_EXT for readback; on GLES fall back to GL_RGBA + byte swizzle.","Ensure the offscreen framebuffer is still bound and complete immediately before ReadPixels (re-check status).","Catch InvalidOperationException around the render pass and stop further rendering of this element (the surrounding code already logs and disables rendering)."],"exampleFix":"// before\n_gl.ReadPixels(0, 0, w, h, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);\nif (_gl.GetError() is var e && e is not GLEnum.NoError)\n{\n\tthrow new InvalidOperationException($\"readback failed with {e}\");\n}\n\n// after (graceful degrade)\n_gl.ReadPixels(0, 0, w, h, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);\nif (_gl.GetError() is var e && e is not GLEnum.NoError)\n{\n\tthis.Log().Error($\"readback failed with {e}; element will render blank.\");\n\treturn;\n}","handlingStrategy":"try-catch","validationCode":"// Verify framebuffer still complete right before readback\nif (_gl.CheckFramebufferStatus(GLEnum.Framebuffer) != GLEnum.FramebufferComplete) return;","typeGuard":null,"tryCatchPattern":"try { Readback(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"readback\")) { this.Log().Error($\"readback disabled: {ex}\"); }","preventionTips":["Keep the offscreen framebuffer bound during readback.","On GLES, avoid GL_BGRA for readback; use GL_RGBA and swizzle.","Wrap the render pass so a readback failure disables the element instead of crashing the app."],"tags":["opengl","glcanvaselement","readback","driver","graphics"],"backgroundTag":null,"analyzedSha":"04183404888ea21b4e5bfa3493e8d5f15e972c3a","analyzedAt":"2026-08-13T21:08:11.651Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}