linebender/druid · error

invalid screen num

Error message

invalid screen num: {}

What it means

Thrown by the internal create_event_window helper when the screen_num index is out of bounds of the X connection's roots (setup().roots.get returned None). This is the same class of failure as Application::new's "Invalid screen num", but occurs while creating the special event/multiplexing window, so it surfaces after the application has already validated its own screen argument.

Solutions

  1. Reconnect/restart the application after any X server restart so it re-reads the current screen configuration.
  2. Use screen index 0 or validate against setup().roots.len() before creating windows.
  3. Verify the DISPLAY environment variable matches the actual server's screen layout (xdpyinfo | grep dimensions per screen).
Defensive patterns

Strategy: validation

Validate before calling

let n = conn.setup().roots.len();
if screen_num >= n { return Err(anyhow!("screen_num {} >= {} screens", screen_num, n)); }

Prevention

When it happens

Trigger: create_event_window invoked with a screen_num larger than the number of screens the X server reports — e.g. a screen index captured before an X server restart (screens reduced), or a mismatch between the screen stored in Application state and the live connection.

Common situations: Long-running processes after the X server restarted with a different configuration; X11 forwarding sessions whose screen count changed; environments using multi-screen DISPLAY values (e.g. :0.1) that the new server doesn't support.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

    #[inline]
    pub(crate) fn present_opcode(&self) -> Option<u8> {
        self.present_opcode
    }

    /// Return the ARGB32 pictformat of the server, but only if RENDER's CreateCursor is supported
    #[inline]
    pub(crate) fn render_argb32_pictformat_cursor(&self) -> Option<Pictformat> {
        self.render_argb32_pictformat_cursor
    }

    fn create_event_window(conn: &Rc<XCBConnection>, screen_num: usize) -> Result<u32, Error> {
        let id = conn.generate_id()?;
        let setup = conn.setup();
        let screen = setup
            .roots
            .get(screen_num)
            .ok_or_else(|| anyhow!("invalid screen num: {}", screen_num))?;

        // Create the actual window
        conn.create_window(
            // Window depth
            x11rb::COPY_FROM_PARENT.try_into().unwrap(),
            // The new window's ID
            id,
            // Parent window of this new window
            screen.root,
            // X-coordinate of the new window
            0,
            // Y-coordinate of the new window
            0,
            // Width of the new window
            1,
            // Height of the new window
            1,
            // Border width

View on GitHub (pinned to 0f8b1195e4)