iced-rs/iced · critical

Create event loop

Error message

Create event loop

What it means

This panic occurs when winit's EventLoop::with_user_event().build() returns an error inside iced_winit::run (winit/src/lib.rs:81-83), before any window exists. EventLoopError means the platform could not initialize its event loop: on Linux there is no connection to a display server (no X11 via DISPLAY and no Wayland via WAYLAND_DISPLAY), and on any platform creating a second event loop in the same process fails (RecreationAttempt). Because iced unwraps with .expect("Create event loop"), the application dies at startup with this message.

Source

Thrown at winit/src/lib.rs:83

use std::mem::ManuallyDrop;
use std::slice;
use std::sync::Arc;

/// Runs a [`Program`] with the provided settings.
pub fn run<P>(program: P) -> Result<(), Error>
where
    P: Program + 'static,
    P::Theme: theme::Base,
{
    use winit::event_loop::EventLoop;

    let boot_span = debug::boot();
    let settings = program.settings();
    let window_settings = program.window();

    let event_loop = EventLoop::with_user_event()
        .build()
        .expect("Create event loop");

    let backend_settings = backend::Settings::from(&settings);
    let renderer_settings = renderer::Settings::from(&settings);
    let display_handle = event_loop.owned_display_handle();

    let (proxy, worker) = Proxy::new(event_loop.create_proxy());

    #[cfg(feature = "debug")]
    {
        let proxy = proxy.clone();

        debug::on_hotpatch(move || {
            proxy.send_action(Action::Reload);
        });
    }

    let mut runtime = {
        let executor = P::Executor::new().map_err(Error::ExecutorCreationFailed)?;

View on GitHub (pinned to 2cffa99b39)

Solutions

  1. Provide a display: in CI/Docker run under `xvfb-run -a cargo test` / `xvfb-run -a ./app`; over SSH use `ssh -X` or `ssh -Y`, or set DISPLAY to a reachable X server.
  2. On Wayland ensure WAYLAND_DISPLAY points at a live socket (check `ls $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY`); on X11 verify with `echo $DISPLAY` and `xdpyinfo`.
  3. Never create the event loop twice in one process: call iced::run exactly once from main(); in integration tests run one app per test binary, spawn each case as a child process, or test UI logic with iced's headless runtime APIs instead of the full shell.
  4. If the failure is a missing library rather than a missing display, install the X11 stack (libxcb, libxkbcommon, libxkbcommon-x11) or build iced with only the `wayland` feature to drop the X11 dependency entirely.
  5. If you need no window at all (render to an image, offscreen compositing), use wgpu headlessly or iced's headless rendering support instead of iced_winit::run.

Example fix

// before — panics with "Create event loop" in headless CI/containers
fn main() -> iced::Result {
    iced::run("Todo", Todos::update, Todos::view)
}

// after — fail fast with an actionable message instead of a winit panic
fn main() -> iced::Result {
    #[cfg(target_os = "linux")]
    if std::env::var("DISPLAY").is_err() && std::env::var("WAYLAND_DISPLAY").is_err() {
        eprintln!("no display server found: set DISPLAY/WAYLAND_DISPLAY or run under xvfb-run");
        std::process::exit(64);
    }
    iced::run("Todo", Todos::update, Todos::view)
}
Defensive patterns

Strategy: validation

Validate before calling

// Run before calling iced::run / any winit API on Linux
fn display_available() -> bool {
    std::env::var("DISPLAY").is_ok() || std::env::var("WAYLAND_DISPLAY").is_ok()
}

fn main() -> iced::Result {
    #[cfg(target_os = "linux")]
    if !display_available() {
        eprintln!("no display server: set DISPLAY/WAYLAND_DISPLAY or run under xvfb-run");
        std::process::exit(64);
    }
    iced::run("App", Update::new, View::new)
}

# CI equivalent: xvfb-run -a cargo test -- --nocapture

Prevention

When it happens

Trigger: Running the binary where no display server is reachable: Docker containers, CI runners, systemd services, cron — DISPLAY and WAYLAND_DISPLAY unset; SSH sessions without X11 forwarding; a Wayland session whose compositor socket under $XDG_RUNTIME_DIR is gone; calling iced::run (or otherwise constructing an EventLoop) a second time in one process, e.g. two invocations in the same integration-test binary; on macOS, initializing the event loop off the main thread.

Common situations: GUI apps that also run in CI or containers without Xvfb; test harnesses that boot the full iced runtime per #[test] function; running the GUI binary over plain ssh; distro/minimal images where libxcb/libxkbcommon-x11 are missing so the X11 connect fails; switching sessions between X11 and Wayland with stale environment variables.

Related errors


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/2d2f68efa10e297b. Report an issue: GitHub.