{"record":{"id":"506981f1f72cf9ff","repo":"emilk/egui","slug":"you-must-call-update-buffers-before-render","errorCode":null,"errorMessage":"You must call .update_buffers() before .render()","messagePattern":"You must call \\.update_buffers\\(\\) before \\.render\\(\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/egui-wgpu/src/renderer.rs","lineNumber":552,"sourceCode":"                    size_in_pixels[1] as f32,\n                    0.0,\n                    1.0,\n                );\n                render_pass.set_pipeline(&self.pipeline);\n                render_pass.set_bind_group(0, &self.uniform_bind_group, &[]);\n                needs_reset = false;\n            }\n\n            {\n                let rect = ScissorRect::new(clip_rect, pixels_per_point, size_in_pixels);\n\n                if rect.width == 0 || rect.height == 0 {\n                    // Skip rendering zero-sized clip areas.\n                    if let Primitive::Mesh(_) = primitive {\n                        // If this is a mesh, we need to advance the index and vertex buffer iterators:\n                        index_buffer_slices\n                            .next()\n                            .expect(\"You must call .update_buffers() before .render()\");\n                        vertex_buffer_slices\n                            .next()\n                            .expect(\"You must call .update_buffers() before .render()\");\n                    }\n                    continue;\n                }\n\n                render_pass.set_scissor_rect(rect.x, rect.y, rect.width, rect.height);\n            }\n\n            match primitive {\n                Primitive::Mesh(mesh) => {\n                    let index_buffer_slice = index_buffer_slices\n                        .next()\n                        .expect(\"You must call .update_buffers() before .render()\");\n                    let vertex_buffer_slice = vertex_buffer_slices\n                        .next()\n                        .expect(\"You must call .update_buffers() before .render()\");","sourceCodeStart":534,"sourceCodeEnd":570,"githubUrl":"https://github.com/emilk/egui/blob/441971a776322a482e371775219380eca812cfa9/crates/egui-wgpu/src/renderer.rs#L534-L570","documentation":"In egui-wgpu's renderer, render() advances pre-built buffer slice iterators for each mesh. If the iterators are empty, render was called without a prior update_buffers() call, so the slices from the uploaded buffers don't match the painted primitives. The library panics because continuing would render garbage indices.","triggerScenarios":"Calling CallbackTrait::render (or egui_wgpu::Renderer::render) directly without calling renderer.update_buffers(...) first for the same screen descriptor and clipped primitives, in a custom integration or custom paint callback.","commonSituations":"Custom egui-wgpu integrations written before/without update_buffers (API added to fix multi-mesh rendering); users overriding render in a paint callback; porting older integration code to a newer egui-wgpu where render no longer does buffer uploads itself.","solutions":["Call renderer.update_buffers(device, queue, encoder, clipped_primitives, screen_descriptor) before render and pass the returned Vec<BufferDimensions> usage onward.","Use the standard egui_wgpu::Renderer::render flow (it manages update_buffers internally) rather than a custom one.","Update integration code copied from outdated examples to the current egui-wgpu render pattern."],"exampleFix":"// before\nrenderer.render(&mut render_pass, &clipped_primitives, &screen);\n// after\nlet buffer_slices = renderer.update_buffers(&device, &queue, &mut encoder, &clipped_primitives, &screen);\nrenderer.render(&mut render_pass, &clipped_primitives, &buffer_slices, &screen);","handlingStrategy":"validation","validationCode":"// Ensure this ran in the same frame:\n// let slices = renderer.update_buffers(&device, &queue, &mut encoder, &clipped_primitives, &screen_descriptor);","typeGuard":"fn slices_ready(slices: &[egui_wgpu::BufferDimensions], prims: &[ClippedPrimitive]) -> bool { !prims.iter().any(|p| matches!(p.primitive, Primitive::Mesh(_))) || !slices.is_empty() }","tryCatchPattern":"// Panic in release too; not catchable per-call. Prevent by structuring code so update_buffers always precedes render.","preventionTips":["Always call update_buffers immediately before render with identical primitives.","Pass update_buffers' return value directly into render.","Follow the current official egui-wgpu/eframe integration example."],"tags":["wgpu","rendering","api-misuse","panic"],"backgroundTag":"invalid-state-transition","analyzedSha":"441971a776322a482e371775219380eca812cfa9","analyzedAt":"2026-09-12T04:29:21.500Z","contentChangedAt":"2026-09-12T04:29:21.500Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}