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
- Run the application under a real display: set DISPLAY for X11/XWayland or WAYLAND_DISPLAY for Wayland
- Re-enable the matching platform feature: iced = { features = ["tiny-skia", "x11"] } or "wayland" (they forward to softbuffer/x11 and softbuffer/wayland)
- Verify the window handle type matches the active session (X11 window + Wayland session requires XWayland)
- 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
- Keep the x11 and wayland features enabled on iced/iced_tiny_skia; they are what re-enable softbuffer backends (softbuffer is pinned with default-features = false)
- Smoke-test window creation in CI with xvfb-run so a missing backend fails the build, not users
- Confirm the window's platform matches the session (X11 window under Wayland needs XWayland)
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
.windowView on GitHub (pinned to 3de451447b)