emilk/egui · error
Single-use AppCreator has unexpectedly already been taken
Error message
Single-use AppCreator has unexpectedly already been taken
What it means
`app_creator` is a `Option<AppCreator>` consumed exactly once during startup: `init_run_state` does `core::mem::take(&mut self.app_creator)` and panics if it was already `None`. This enforces the single-use contract — the closure that builds your `App` must run exactly once when the first window/viewport initializes. Seeing this panic means `init_run_state` was entered twice (or the creator was taken elsewhere), which is an internal state machine violation.
Source
Thrown at crates/eframe/src/native/wgpu_integration.rs:314
#[allow(clippy::allow_attributes, unused_mut)] // used for accesskit
let mut egui_winit = egui_winit::State::new(
egui_ctx.clone(),
ViewportId::ROOT,
event_loop,
Some(window.scale_factor() as f32),
event_loop.system_theme(),
painter.max_texture_side(),
);
#[cfg(feature = "accesskit")]
{
let event_loop_proxy = self.repaint_proxy.lock().clone();
egui_winit.init_accesskit(event_loop, &window, event_loop_proxy);
}
let app_creator = core::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken");
crate::maybe_attach_inspection_plugin(&egui_ctx, Some(self.app_name.clone()));
let cc = CreationContext {
egui_ctx: egui_ctx.clone(),
integration_info: integration.frame.info().clone(),
storage: integration.frame.storage(),
#[cfg(feature = "glow")]
gl: None,
#[cfg(feature = "glow")]
get_proc_address: None,
wgpu_render_state,
window: Some(Arc::clone(&window)),
raw_display_handle: window.display_handle().map(|h| h.as_raw()),
raw_window_handle: window.window_handle().map(|h| h.as_raw()),
};
let app = {
profiling::scope!("user_app_creator");View on GitHub (pinned to 441971a776)
Solutions
- Ensure `run_native`/`eframe::run_simple_native` is called once per process and the event loop is not restarted with reused state.
- Create a fresh `NativeOptions` and let eframe construct its own run state instead of reusing or caching integration state.
- In custom integrations, check that only one viewport initialization path calls `init_run_state`/consumes `app_creator`.
- If using the wasm/web backend with hot-reload, make sure state isn't carried across reloads into a second init.
Example fix
// before: reusing state across a manual event-loop restart let mut state = RunState::new(options, app_creator); // ... later, with the same state state.init_run_state(&event_loop)?; // panics if already taken // after: build a fresh run state each time you start an event loop let mut state = RunState::new(fresh_options, app_creator); state.init_run_state(&event_loop)?;
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the creator is still available before re-running init
fn ensure_creator(state: &RunState) -> Result<(), String> {
if state.app_creator.is_none() {
return Err("AppCreator already consumed; build a fresh RunState".into());
}
Ok(())
} Prevention
- Call run_native once per process; never reuse RunState/NativeOptions across event-loop restarts
- Let eframe own initialization instead of calling init_run_state manually
- Recreate all state when restarting the event loop (e.g. after wasm reload)
When it happens
Trigger: Calling `init_run_state` twice on the same `RunState`/integration (e.g. re-initializing after the event loop restarted), or a viewport-instantiation path that runs while a previous initialization already consumed the `AppCreator`.
Common situations: Custom multi-viewport setups where the app-creation hook fires twice; embedding eframe and manually restarting the event loop with the same options/state; forks or patched integrations that call init paths directly.
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
- Single-use AppCreator has unexpectedly already been taken
- failed to fit multisamples option of native_options into u8
- Failed to get window handle
- viewport doesn't exist
- Failed to get display handle
AI-assisted analysis of emilk/egui@441971a776 (2026-09-12).
Data as JSON: /api/errors/f731f35737cbdb28.
Report an issue: GitHub.