elkowar/eww · error

could not get default display

Error message

could not get default display

What it means

`wait_for_monitor_model` polls the GDK display until every connected monitor reports a model string, which eww uses to build its monitor model. `gdk::Display::default()` returned `None`, meaning no default display is available in this process, and the `expect` panics with this message. Without a display there is nothing to wait on.

Solutions

  1. Ensure `DISPLAY` (X11) or `WAYLAND_DISPLAY`/`XDG_RUNTIME_DIR` env vars are set to a live session before invoking eww.
  2. Run eww inside the graphical session, e.g. via `systemctl --user import-environment DISPLAY WAYLAND_DISPLAY` or launching from the compositor's autostart.
  3. Retry after the window manager/session is up; the call will succeed once a display exists.

Example fix

// before (crontab/systemd unit)
ExecStart = eww daemon
// after
ExecStart = /bin/sh -c '. $HOME/.profile && exec eww daemon'  # with DISPLAY exported
Defensive patterns

Strategy: try-catch

Validate before calling

if std::env::var("DISPLAY").is_err() && std::env::var("WAYLAND_DISPLAY").is_err() {
    eprintln!("no graphical session: set DISPLAY or WAYLAND_DISPLAY before running eww");
    std::process::exit(1);
}

Try / catch

match gdk::Display::default() {
    Some(display) => /* poll monitors */,
    None => eprintln!("no default display; is the graphical session running?"),
}

Prevention

When it happens

Trigger: Calling `try_handle_command` → `wait_for_monitor_model` in an environment where GTK/GDK cannot open a default display: no X server/Wayland compositor, or DISPLAY/WAYLAND_DISPLAY unset.

Common situations: Running `eww` commands from a systemd service, cron job, SSH session, or TTY where `DISPLAY` is not set; starting eww before the compositor/X server.


AI-assisted analysis of elkowar/eww@48f5aa8b37 (2026-09-08). Data as JSON: /api/errors/f852eaaf1f9125de. Report an issue: GitHub.

Appendix: source

Thrown at crates/eww/src/app.rs:153

    pub phantom: PhantomData<B>,
}

impl<B: DisplayBackend> std::fmt::Debug for App<B> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("App")
            .field("scope_graph", &*self.scope_graph.borrow())
            .field("eww_config", &self.eww_config)
            .field("open_windows", &self.open_windows)
            .field("failed_windows", &self.failed_windows)
            .field("window_arguments", &self.instance_id_to_args)
            .field("paths", &self.paths)
            .finish()
    }
}

/// Wait until the .model() is available for all monitors (or there is a timeout)
async fn wait_for_monitor_model() {
    let display = gdk::Display::default().expect("could not get default display");
    let start = std::time::Instant::now();
    loop {
        let all_monitors_set =
            (0..display.n_monitors()).all(|i| display.monitor(i).and_then(|monitor| monitor.model()).is_some());
        if all_monitors_set {
            break;
        }
        tokio::time::sleep(Duration::from_millis(10)).await;
        if std::time::Instant::now() - start > Duration::from_millis(500) {
            log::warn!("Timed out waiting for monitor model to be set");
            break;
        }
    }
}

impl<B: DisplayBackend> App<B> {
    /// Handle a [`DaemonCommand`] event, logging any errors that occur.
    pub async fn handle_command(&mut self, event: DaemonCommand) {

View on GitHub (pinned to 48f5aa8b37)