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
- Restart the X server with a standard configuration (default depth 24, e.g. Xvfb :1 -screen 0 1024x768x24).
- Try a different screen index via Application::new(None, 0) to rule out a per-screen problem.
- Bypass SSH X forwarding / VNC proxies and test against a local X server to confirm the environment is the cause.
- 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
- Run X servers with standard visual configs (default depth 24).
- Avoid untested VNC/remote-X proxies in production runs.
- Capture xdpyinfo output in diagnostics bundles for reproducibility.
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
- Invalid screen num
- invalid screen num
- No window with id
- didn't get any modes
- Failed to update cairo drawable
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(×tamp),
);
let primary = Clipboard::new(
Rc::clone(&connection),
screen_num,
Rc::clone(&atoms),
atoms.PRIMARY,
Rc::clone(&pending_events),View on GitHub (pinned to 0f8b1195e4)