linebender/druid · error
attaching an already in-use surface
Error message
attaching an already in-use surface
What it means
`Buffer::attach` panics if the buffer is already flagged `in_use`, meaning it is still attached to a surface and has not been released by the compositor. Attaching it again would give two surfaces the same buffer, which the Wayland protocol forbids.
Solutions
- Increase the buffer pool size so a free buffer is always available
- Wait for buffer release (frame callbacks / `wl_buffer.release`) before reattaching
- Ensure buffers are properly marked released on the release event so `in_use` is cleared
Example fix
// before
let buf = self.buffers[index].clone();
buf.attach(&surface); // may still be in_use
// after
let buf = self.buffers.iter().find(|b| !b.in_use.get())
.expect("no free buffer; grow pool or wait for release");
buf.attach(&surface); Defensive patterns
Strategy: validation
Validate before calling
if buffer_in_use(buffer) { pick_free_buffer_or_wait_for_release() } else { buffer.attach(&surface) } Type guard
fn is_free(b: &Buffer) -> bool { !b.in_use.get() } Prevention
- Always select buffers via a free-buffer check before attach
- Size the buffer pool generously for high-frequency redraws and resizes
- Handle `wl_buffer.release` promptly so `in_use` flags clear correctly
When it happens
Trigger: The surface code selects a buffer from the pool that has not yet been released (e.g. all buffers busy) and calls `attach` on it a second time before the release event arrives.
Common situations: Fast resize/redraw sequences exhausting the buffer pool; a missing/compositor bug in buffer release handling causing stale `in_use` flags.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- called request_paint during painting
- unexpected wayland event
- unrecognised key event
- unable to acquire underlying compositor to create an xdg…
- unable to acquire underlying compositor to create an xdg…
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/3aed0bbbba32eaf5.
Report an issue: GitHub.
Appendix: source
Thrown at druid-shell/src/backend/wayland/surfaces/buffers.rs:285
let inner = pool.create_buffer(offset, width, height, stride, wl_shm::Format::Argb8888);
let in_use = Rc::new(Cell::new(false));
inner.quick_assign(with_cloned!(in_use; move |b, event, _dispatchdata| {
tracing::trace!("buffer event: {:?} {:?}", b, event);
match event {
wl_buffer::Event::Release => {
in_use.set(false);
}
_ => tracing::warn!("unhandled wayland buffer event: {:?} {:?}", b, event),
}
}));
Buffer { inner, in_use }
}
pub fn attach(&self, wl_surface: &wl::Main<WlSurface>) {
if self.in_use.get() {
panic!("attaching an already in-use surface");
}
self.in_use.set(true);
wl_surface.attach(Some(&self.inner), 0, 0);
}
pub fn destroy(&self) {
if self.in_use.get() {
panic!("Destroying a buffer while it is in use");
}
self.inner.destroy();
}
}
pub struct BufferData<const N: usize> {
buffers: WeakRc<Buffers<N>>,
mmap: Mmap,
}
View on GitHub (pinned to 0f8b1195e4)