linebender/druid · error

Couldn't get visual from screen

Error message

Couldn't get visual from screen

What it means

Thrown by Application::new when util::get_visual_from_screen returns None, i.e. the chosen screen's root visual could not be resolved from the X server's setup data. This indicates the screen record lacks a usable root_visual or the lookup failed, so windows cannot be created with a valid visual (depth/colormap combination).

Solutions

  1. Restart the X server with a standard configuration (default depth 24, e.g. Xvfb :1 -screen 0 1024x768x24).
  2. Try a different screen index via Application::new(None, 0) to rule out a per-screen problem.
  3. Bypass SSH X forwarding / VNC proxies and test against a local X server to confirm the environment is the cause.
  4. If it persists, file an issue with `xdpyinfo` output showing available visuals for the failing screen.

Example fix

// before (headless CI)
Xvfb :1 -screen 0 1024x768x8
// after
Xvfb :1 -screen 0 1024x768x24
Defensive patterns

Strategy: try-catch

Validate before calling

// check visuals exist via xdpyinfo output before launching, or at runtime:
let setup = conn.setup();
let ok = setup.roots.iter().any(|s| util::get_visual_from_screen(s).is_some());

Try / catch

match Application::new(None, 0) {
    Ok(app) => app,
    Err(e) if e.to_string().contains("Couldn't get visual from screen") => {
        eprintln!("X server reports no usable visual; restart X with depth 24");
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Application::new called against a screen whose root visual id does not resolve in setup().visual_formats / depth lists — typically a broken or exotic X server configuration, a screen obtained incorrectly (e.g. bad screen_num leading to a different code path), or corrupted X11 setup data from a misbehaving proxy (Xvnc, x11vnc, X forwarding).

Common situations: Running under VNC/remote-X proxies with incomplete visual setup; running on nested/specialized servers (Xephyr, some Wayland XWayland edge cases); hardware driver misconfiguration leaving no usable root visual; automated environments (Xvfb with unusual -screen depth options).

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at druid-shell/src/backend/x11/application.rs:303

            crosshair: load_cursor("crosshair"),
            not_allowed: load_cursor("not-allowed"),
            row_resize: load_cursor("row-resize"),
            col_resize: load_cursor("col-resize"),
        };

        let atoms = Rc::new(
            AppAtoms::new(&*connection)?
                .reply()
                .context("get X11 atoms")?,
        );

        let screen = connection
            .setup()
            .roots
            .get(screen_num)
            .ok_or_else(|| anyhow!("Invalid screen num: {}", screen_num))?;
        let root_visual_type = util::get_visual_from_screen(screen)
            .ok_or_else(|| anyhow!("Couldn't get visual from screen"))?;
        let argb_visual_type = util::get_argb_visual_type(&connection, screen)?;

        let timestamp = Rc::new(Cell::new(x11rb::CURRENT_TIME));
        let pending_events = Default::default();
        let clipboard = Clipboard::new(
            Rc::clone(&connection),
            screen_num,
            Rc::clone(&atoms),
            atoms.CLIPBOARD,
            Rc::clone(&pending_events),
            Rc::clone(&timestamp),
        );
        let primary = Clipboard::new(
            Rc::clone(&connection),
            screen_num,
            Rc::clone(&atoms),
            atoms.PRIMARY,
            Rc::clone(&pending_events),

View on GitHub (pinned to 0f8b1195e4)