emilk/egui · critical
Single-use AppCreator has unexpectedly already been taken
Error message
Single-use AppCreator has unexpectedly already been taken
What it means
eframe stores your AppCreator closure in an Option and consumes it exactly once with core::mem::take when the root viewport is first created inside the event loop. This expect fires when the creation path is entered a second time after the closure was already taken: the event loop delivered Resumed/init twice (classic Android suspend/resume lifecycle) or the runner state was re-entered after a restart.
Source
Thrown at crates/eframe/src/native/glow_integration.rs:343
..
} = viewport
{
egui_winit.init_accesskit(event_loop, window, event_loop_proxy);
}
}
if self
.native_options
.viewport
.mouse_passthrough
.unwrap_or(false)
&& let Err(err) = glutin.window(ViewportId::ROOT).set_cursor_hittest(false)
{
log::warn!("set_cursor_hittest(false) failed: {err}");
}
let app_creator = core::mem::take(&mut self.app_creator)
.expect("Single-use AppCreator has unexpectedly already been taken");
crate::maybe_attach_inspection_plugin(&integration.egui_ctx, Some(self.app_name.clone()));
let app: Box<dyn 'app + App> = {
// Use latest raw_window_handle for eframe compatibility
use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
let gl_config = glutin.gl_config.clone();
let get_proc_address = move |addr: &_| gl_config.display().get_proc_address(addr);
let window = glutin.window(ViewportId::ROOT);
let cc = CreationContext {
egui_ctx: integration.egui_ctx.clone(),
integration_info: integration.frame.info().clone(),
storage: integration.frame.storage(),
gl: Some(gl),
get_proc_address: Some(Arc::new(get_proc_address)),
#[cfg(feature = "wgpu_no_default_features")]
wgpu_render_state: None,View on GitHub (pinned to d802a982ce)
Solutions
- Update eframe to the latest patch release (Android lifecycle double-resume handling has been fixed and refactored over time).
- Ensure run_native / the event loop is started exactly once per process.
- On Android, treat Activity recreation as a fresh process: recreate the runner state instead of re-entering the old one.
- If reproducible on current eframe, report with the backtrace and lifecycle events seen.
Defensive patterns
Strategy: validation
Prevention
- Call eframe::run_native (or start the event loop) exactly once per process; never reuse a runner after it has run.
- On Android, assume Activity recreation starts a fresh run; do not cache eframe runner state across suspend/resume.
- Track eframe patch releases — lifecycle double-resume fixes land there.
- Set RUST_BACKTRACE=1 in dev builds so a hit shows which event path re-entered creation.
When it happens
Trigger: Entering the Glow backend's root-window creation twice in one process: duplicate winit Resumed events on Android, re-running the event loop on a reused runner, or a winit/eframe version mismatch that re-delivers initialization events.
Common situations: Android apps where the Activity is suspended and recreated (second Resumed event); upgrading winit across event-loop API changes; embedding eframe in a host framework that restarts the GUI loop in the same process.
Related errors
- failed to fit multisamples option of native_options into u8
- failed to construct C string from string for gl proc address
AI-assisted analysis of emilk/egui@d802a982ce (2026-08-16).
Data as JSON: /api/errors/934fafe0da2d79af.
Report an issue: GitHub.