iced-rs/iced · critical

Create softbuffer surface for window

Error message

Create softbuffer surface for window

What it means

iced's tiny-skia software renderer wraps every window in a softbuffer::Surface to obtain a CPU-writable backbuffer. softbuffer 0.4 returns Err from Surface::new when it cannot turn the window's raw window handle into a platform surface: the backend matching the handle (X11, Wayland, Win32, AppKit) is unavailable, was compiled out, or the handle is not yet valid. iced treats this as unrecoverable and panics via .expect("Create softbuffer surface for window").

Solutions

  1. Run the application under a real display: set DISPLAY for X11/XWayland or WAYLAND_DISPLAY for Wayland
  2. Re-enable the matching platform feature: iced = { features = ["tiny-skia", "x11"] } or "wayland" (they forward to softbuffer/x11 and softbuffer/wayland)
  3. Verify the window handle type matches the active session (X11 window + Wayland session requires XWayland)
  4. If no display server is available at all, switch to the wgpu renderer or use the offscreen screenshot() path instead of a window surface

Example fix

// before (Cargo.toml)
[dependencies]
iced = { version = "0.13", default-features = false, features = ["tiny-skia"] }

// after
[dependencies]
iced = { version = "0.13", default-features = false, features = ["tiny-skia", "x11", "wayland"] }
Defensive patterns

Strategy: validation

Validate before calling

// Before starting a tiny-skia (software) iced app on Linux:
fn display_available() -> bool {
    std::env::var("DISPLAY").is_ok() || std::env::var("WAYLAND_DISPLAY").is_ok()
}

if !display_available() {
    eprintln!("no display server: enable iced x11/wayland features or run under XWayland");
    std::process::exit(1);
}

Prevention

When it happens

Trigger: Running an iced application with the tiny-skia renderer when the window's platform handle does not match an available softbuffer backend: an X11 window under a Wayland session without XWayland, or a build of iced_tiny_skia/iced with default-features = false where the x11/wayland features (which forward to softbuffer/x11, softbuffer/wayland per tiny_skia/Cargo.toml:23-24) were dropped. Also triggered when create_surface is called before the window is fully realized on platforms where the raw handle is incomplete.

Common situations: Headless CI machines and Docker/SSH sessions with no display server; minimal feature-trimmed builds for embedded Linux boards (workspace pins softbuffer = { version = "0.4", default-features = false }); X11-vs-Wayland mismatches in Flatpak/sandboxed environments; softbuffer 0.3 to 0.4 upgrades where platform feature names changed.

Related errors


AI-assisted analysis of iced-rs/iced@3de451447b (2026-08-17). Data as JSON: /api/errors/3c8f90a25805d8a8. Report an issue: GitHub.

Appendix: source

Thrown at tiny_skia/src/window/compositor.rs:62

                },
            });
        }

        Ok(new(display))
    }

    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {
        Renderer::new(settings)
    }

    fn create_surface(
        &mut self,
        window: impl compositor::Window + Clone,
        width: u32,
        height: u32,
    ) -> Self::Surface {
        let window = softbuffer::Surface::new(&self.context, Box::new(window.clone()) as _)
            .expect("Create softbuffer surface for window");

        let mut surface = Surface {
            window,
            clip_mask: tiny_skia::Mask::new(1, 1).expect("Create clip mask"),
            frames: VecDeque::new(),
            max_age: 0,
        };

        if width > 0 && height > 0 {
            self.configure_surface(&mut surface, width, height);
        }

        surface
    }

    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {
        surface
            .window

View on GitHub (pinned to 3de451447b)