linebender/druid · critical

failed to initialize the displays event loop!

Error message

failed to initialize the displays event loop!

What it means

The Wayland outputs/displays module builds a calloop event loop to track monitor (output) metadata changes, initializing a per-display BTreeMap cache. If calloop::EventLoop::try_new() fails while setting up this loop in current(), the code panics with expect and this message, aborting display-information initialization.

Solutions

  1. Raise the file-descriptor limit (`ulimit -n`) and audit for fd leaks in the process.
  2. Adjust sandbox/seccomp profiles to allow epoll syscalls; test by running unsandboxed.
  3. Free memory / check for OOM conditions at startup.
  4. Patch or upgrade so failure falls back to a cached/empty display list instead of panicking.
  5. Update druid-shell; newer revisions reworked wayland output handling.

Example fix

// before
let mut eventloop = calloop::EventLoop::try_new()
    .expect("failed to initialize the displays event loop!");

// after
let mut eventloop = calloop::EventLoop::try_new()
    .map_err(|e| tracing::error!("displays event loop init failed: {e}"))
    .unwrap_or_default_fallback(); // degrade to polling display list once at startup
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight epoll availability before display enumeration
let epoll_ok = unsafe { libc::epoll_create1(0) } >= 0;
if !epoll_ok { /* fall back to one-shot display query */ }

Try / catch

match calloop::EventLoop::try_new() {
    Ok(el) => run_display_loop(el),
    Err(e) => {
        log::error!("displays loop init failed: {e}");
        // fall back to a static snapshot of outputs
    }
}

Prevention

When it happens

Trigger: calloop EventLoop::try_new() returning Err — epoll_create1 failure from exhausted file descriptors, sandboxed syscall filters (seccomp), or memory pressure — when current() is called to enumerate displays on Wayland.

Common situations: Apps launched under Flatpak/Snap with restrictive sandboxing; systems at the fd limit (many open windows/sockets or leaking fds); embedded Wayland environments; multi-monitor setups querying display metadata at startup.

Related errors


AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10). Data as JSON: /api/errors/1d6b97d200990c92. Report an issue: GitHub.

Appendix: source

Thrown at druid-shell/src/backend/wayland/outputs/mod.rs:38

) -> Result<calloop::channel::Channel<Event>, error::Error> {
    tracing::debug!("detecting xdg outputs");
    match output::detect(env) {
        Ok(rx) => return Ok(rx),
        Err(cause) => tracing::info!("unable to detect xdg outputs {:?}", cause),
    }

    Err(error::Error::string("unable to detect display outputs"))
}

pub(super) fn current() -> Result<Vec<Meta>, error::Error> {
    let dispatcher = display::Dispatcher::default();
    let rx = auto(&dispatcher)?;
    let env = display::new(dispatcher)?;
    let mut cache = std::collections::BTreeMap::new();
    let mut eventloop: calloop::EventLoop<(
        calloop::LoopSignal,
        &mut std::collections::BTreeMap<String, Meta>,
    )> = calloop::EventLoop::try_new().expect("failed to initialize the displays event loop!");
    let signal = eventloop.get_signal();
    let handle = eventloop.handle();
    handle
        .insert_source(rx, {
            move |event, _ignored, (signal, cache)| {
                let event = match event {
                    calloop::channel::Event::Msg(event) => event,
                    calloop::channel::Event::Closed => return signal.stop(),
                };

                match event {
                    Event::Located(meta) => {
                        cache.insert(meta.name.clone(), meta);
                    }
                    Event::Removed(meta) => {
                        cache.remove(&meta.name);
                    }
                }

View on GitHub (pinned to 0f8b1195e4)