linebender/druid · critical

unable to create surface

Error message

unable to create surface

What it means

Surface::new asks the compositor to allocate a new WlSurface; if the compositor returns None the library panics with this message. This indicates the Wayland compositor refused or failed to create the underlying protocol surface, so no window can be constructed.

Solutions

  1. Verify the Wayland environment is healthy: echo $WAYLAND_DISPLAY / $XDG_RUNTIME_DIR and confirm the socket exists before creating windows.
  2. Test with a known-good compositor (e.g. weston, sway, GNOME Wayland) to rule out compositor-specific limitations.
  3. Check that create_surface returning None is not a stub/test-double behavior in your environment.
  4. Reconnect to the compositor (rebuild the handle) and retry surface creation if the compositor restarted.
Defensive patterns

Strategy: validation

Validate before calling

// Validate the Wayland environment before Surface::new
fn wayland_env_ok() -> bool {
    std::env::var("WAYLAND_DISPLAY").is_ok()
        && std::env::var("XDG_RUNTIME_DIR")
            .map(|d| std::path::Path::new(&d).exists())
            .unwrap_or(false)
}

Try / catch

let surface = std::panic::catch_unwind(AssertUnwindSafe(|| {
    Surface::new(&compositor, handler, size)
}))
.map_err(|_| anyhow::anyhow!("compositor failed to create surface"))?;

Prevention

When it happens

Trigger: Calling Surface::new (public constructor) with a compositor whose create_surface() returns None — i.e. the compositor cannot allocate a new wl_surface at that moment.

Common situations: Connecting to a broken or half-initialized Wayland compositor, WAYLAND_DISPLAY / XDG_RUNTIME_DIR pointing at a stale socket, compositor resource exhaustion, or a custom/test compositor stub that always returns None from create_surface.

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


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

Appendix: source

Thrown at druid-shell/src/backend/wayland/surfaces/surface.rs:50

pub struct Surface {
    pub(super) inner: std::sync::Arc<Data>,
}

impl From<std::sync::Arc<Data>> for Surface {
    fn from(d: std::sync::Arc<Data>) -> Self {
        Self { inner: d }
    }
}

impl Surface {
    pub fn new(
        c: impl Into<CompositorHandle>,
        handler: Box<dyn window::WinHandler>,
        initial_size: kurbo::Size,
    ) -> Self {
        let compositor = CompositorHandle::new(c);
        let wl_surface = match compositor.create_surface() {
            None => panic!("unable to create surface"),
            Some(v) => v,
        };

        let current = std::sync::Arc::new(Data {
            compositor: compositor.clone(),
            wl_surface: RefCell::new(wl_surface),
            outputs: RefCell::new(std::collections::HashSet::new()),
            buffers: buffers::Buffers::new(compositor.shared_mem(), initial_size.into()),
            logical_size: Cell::new(initial_size),
            scale: Cell::new(1),
            anim_frame_requested: Cell::new(false),
            handler: RefCell::new(handler),
            idle_queue: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
            active_text_input: Cell::new(None),
            damaged_region: RefCell::new(Region::EMPTY),
            deferred_tasks: RefCell::new(std::collections::VecDeque::new()),
        });

View on GitHub (pinned to 0f8b1195e4)