linebender/druid · error

Failed to create cairo surface

Error message

Failed to create cairo surface: {}

What it means

Error in create_cairo_surface (x11 window build path): XCBSurface::create failed to wrap the XCB window drawable in a cairo XCB surface, and the cairo Status is formatted into the message. It fires when the cairo/xcb connection, drawable, or visual type is invalid — e.g. unsupported visual, connection creation failure, or cairo rejecting the XCB setup — and is called from build.

Solutions

  1. Verify the visual type obtained for the window is supported (24-bit/32-bit truecolor) before creating the surface
  2. Check that the XCB connection was successfully converted to a cairo connection
  3. Re-create the surface after the window/visual is fully initialized; log the cairo Status for the exact failure
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at druid-shell/src/backend/x11/window.rs:212 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at druid-shell/src/backend/x11/window.rs:212

            CairoXCBConnection::from_raw_none(
                conn.get_raw_xcb_connection() as *mut cairo::ffi::xcb_connection_t
            )
        };
        let cairo_drawable = XCBDrawable(window_id);
        let mut xcb_visual = xcb_visualtype_t::from(*visual_type);
        let cairo_visual_type = unsafe {
            XCBVisualType::from_raw_none(
                &mut xcb_visual as *mut xcb_visualtype_t as *mut cairo::ffi::xcb_visualtype_t,
            )
        };
        let cairo_surface = XCBSurface::create(
            &cairo_xcb_connection,
            &cairo_drawable,
            &cairo_visual_type,
            self.size.width as i32,
            self.size.height as i32,
        )
        .map_err(|status| anyhow!("Failed to create cairo surface: {}", status))?;
        Ok(cairo_surface)
    }

    // TODO(x11/menus): make menus if requested
    pub fn build(self) -> Result<WindowHandle, Error> {
        let conn = self.app.connection();
        let screen_num = self.app.screen_num();
        let id = conn.generate_id()?;
        let setup = conn.setup();

        let env_dpi = std::env::var("DRUID_X11_DPI")
            .ok()
            .map(|x| x.parse::<f64>());

        let scale = match env_dpi.or_else(|| self.app.rdb.get_value("Xft.dpi", "").transpose()) {
            Some(Ok(dpi)) => {
                let scale = dpi / 96.;
                Scale::new(scale, scale)

View on GitHub (pinned to 0f8b1195e4)