emilk/egui · error
install_surface called before render_state initialization
Error message
install_surface called before render_state initialization
What it means
install_surface asserts self.render_state.is_some() before configuring a newly created surface, panicking with "install_surface called before render_state initialization" if the renderer's wgpu render state has not been set up yet. Render state (instance, adapter, device, queue) is normally created once up front; installing or recreating a surface before that initialization completes leaves the code without an adapter/device to query capabilities and configure against, so it panics.
Solutions
- Ensure the egui_wgpu painter/renderer is fully initialized (RenderState created) before calling recreate_surface/add_surface/install_surface — typically create the painter, then install surfaces.
- Defer surface installation until after first-frame initialization: create secondary-window surfaces in a later event-loop iteration once render_state exists.
- If render-state creation can fail, handle that case explicitly and skip surface recreation instead of proceeding with a None render_state.
- When writing custom viewport code, check painter.render_state before touching surfaces and route surface setup through the public painter APIs.
Example fix
// before: installing a surface before render state exists let painter = egui_wgpu::ScreenDescriptorlessPainter::new(...); // render_state not yet created painter.add_surface(surface, viewport_id, 0, 0, false); // panics // after: initialize render state first let painter = egui_wgpu::Painter::new(config); painter.set_window(viewport_id, Some(window.clone()))?; // triggers RenderState init // only then: painter.add_surface(surface, viewport_id, width, height, transparent);
Defensive patterns
Strategy: validation
Validate before calling
// Rust: only install surfaces once render state is initialized
if painter.render_state().is_none() {
painter.set_window(viewport_id, Some(window.clone()))?; // triggers init
} Type guard
fn render_state_ready(painter: &egui_wgpu::Painter) -> bool {
painter.render_state().is_some()
} Prevention
- Complete painter/RenderState initialization before add_surface/recreate_surface calls.
- Create secondary-window surfaces in a later event-loop iteration, not during app construction.
- Handle failed render-state init explicitly (e.g. no compatible adapter) instead of letting surface setup proceed.
When it happens
Trigger: Calling install_surface indirectly via recreate_surface or add_surface before RenderState has been created (e.g. attempting to add a viewport/surface during startup before egui_wgpu::Renderer / RenderState::new finished, or after render_state was taken/failed). Also triggered by calling these internals directly in custom viewport code that runs before set_up / renderer init.
Common situations: Custom multi-viewport code installing surfaces for secondary windows during app construction, before the first frame initialized the painter; async RenderState creation still pending when a window-creation callback fires; a failed/skipped render-state initialization (e.g. no compatible adapter) followed by surface teardown/recreate calls.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Failed to create image
- Failed to create render state
- Failed to create staging buffer for index data. Index count
- Failed to create staging buffer for vertex data. Vertex…
- Failed to get window handle
AI-assisted analysis of emilk/egui@8fb03c9ae9 (2026-09-12).
Data as JSON: /api/errors/99a8b598958b5559.
Report an issue: GitHub.
Appendix: source
Thrown at crates/egui-wgpu/src/winit.rs:262
/// Inserts a freshly created surface into [`Self::surfaces`] and configures it.
///
/// Render state must already be initialised before calling this.
// NOTE: The same assumption is already required by `resize_and_generate_depth_texture_view_and_msaa_view`.
fn install_surface(
&mut self,
surface: wgpu::Surface<'static>,
viewport_id: ViewportId,
width: u32,
height: u32,
resizing: bool,
) {
let alpha_mode = {
// Panic: We use the same failure mode as `resize_and_generate_depth_texture_view_and_msaa_view`
let render_state = self
.render_state
.as_ref()
.expect("install_surface called before render_state initialization");
if self.support_transparent_backbuffer {
let supported_alpha_modes =
surface.get_capabilities(&render_state.adapter).alpha_modes;
// Prefer pre multiplied over post multiplied!
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
wgpu::CompositeAlphaMode::PreMultiplied
} else if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
{
wgpu::CompositeAlphaMode::PostMultiplied
} else {
log::warn!(
"Transparent window was requested, but the active wgpu surface does not support a `CompositeAlphaMode` with transparency."
);
wgpu::CompositeAlphaMode::Auto
}
} else {
wgpu::CompositeAlphaMode::Auto
}View on GitHub (pinned to 8fb03c9ae9)