unoplatform/uno · error · InvalidOperationException
The framebuffer readback failed with {readbackError} while c
Error message
The framebuffer readback failed with {readbackError} while copying the framebuffer to the back buffer. What it means
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.
Source
Thrown at src/AddIns/Uno.WinUI.Graphics3DGL/GLCanvasElement.cs:558
if (_readbackAsRgbaWithSwap)
{
_gl.ReadPixels(0, 0, (uint)RenderSize.Width, (uint)RenderSize.Height, GLEnum.Rgba, GLEnum.UnsignedByte, (void*)ptr);
SwapRedBlue((byte*)ptr, (int)RenderSize.Width * (int)RenderSize.Height);
}
else
{
_gl.ReadPixels(0, 0, (uint)RenderSize.Width, (uint)RenderSize.Height, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);
}
});
_backBuffer.PixelBuffer.Length = (uint)RenderSize.Width * (uint)RenderSize.Height * BytesPerPixel;
#endif
// glReadPixels doesn't throw on failure (e.g. an unsupported readback format); it only
// sets a GL error and leaves the destination buffer untouched, which would show up as
// a permanently blank canvas.
if (_gl.GetError() is var readbackError && readbackError is not GLEnum.NoError)
{
throw new InvalidOperationException(
$"The framebuffer readback failed with {readbackError} while copying the framebuffer to the back buffer.");
}
_backBuffer.Invalidate();
}
catch (Exception e)
{
if (this.Log().IsEnabled(LogLevel.Error))
{
this.Log().Error($"{nameof(GLCanvasElement)} rendering failed. The element will no longer render.", e);
}
IsGLInitialized = false;
}
}
// Decides the readback format once, while the context is current and the element's framebuffer
// is bound (see OnLoaded). Any GLES context can lack BGRA read support, and extension stringsView on GitHub (pinned to 0418340488)
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).
Example fix
// before
_gl.ReadPixels(0, 0, w, h, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);
if (_gl.GetError() is var e && e is not GLEnum.NoError)
{
throw new InvalidOperationException($"readback failed with {e}");
}
// after (graceful degrade)
_gl.ReadPixels(0, 0, w, h, GLEnum.Bgra, GLEnum.UnsignedByte, (void*)ptr);
if (_gl.GetError() is var e && e is not GLEnum.NoError)
{
this.Log().Error($"readback failed with {e}; element will render blank.");
return;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Verify framebuffer still complete right before readback if (_gl.CheckFramebufferStatus(GLEnum.Framebuffer) != GLEnum.FramebufferComplete) return;
Try / catch
try { Readback(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("readback")) { this.Log().Error($"readback disabled: {ex}"); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Offscreen framebuffer is not complete
- GLCanvasElement.IsGLInitializedProperty is read-only.
- PBO round-trip mismatch at byte {i}: got {readBack[i]}, expe
- Vertex shader failed to compile: {infoLog}
- Fragment shader failed to compile: {infoLog}
AI-assisted analysis of unoplatform/uno@0418340488 (2026-08-13).
Data as JSON: /api/errors/aa91de9d0f50614b.
Report an issue: GitHub.