{"record":{"id":"9cffbcd0fd7c1ef0","repo":"linebender/druid","slug":"get-idle-handle-invoked-on-a-dead-surface","errorCode":null,"errorMessage":"get_idle_handle invoked on a dead surface","messagePattern":"get_idle_handle invoked on a dead surface","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-shell/src/backend/wayland/surfaces/surface.rs","lineNumber":662,"sourceCode":"\n    fn request_anim_frame(&self) {\n        tracing::warn!(\"request_anim_frame invoked on a dead surface\")\n    }\n\n    fn remove_text_field(&self, _token: TextFieldToken) {\n        tracing::warn!(\"remove_text_field invoked on a dead surface\")\n    }\n\n    fn set_focused_text_field(&self, _active_field: Option<TextFieldToken>) {\n        tracing::warn!(\"set_focused_text_field invoked on a dead surface\")\n    }\n\n    fn set_input_region(&self, _region: Option<Region>) {\n        tracing::warn!(\"set_input_region invoked on a dead surface\")\n    }\n\n    fn get_idle_handle(&self) -> idle::Handle {\n        panic!(\"get_idle_handle invoked on a dead surface\")\n    }\n\n    fn get_scale(&self) -> Scale {\n        Scale::new(1., 1.)\n    }\n\n    fn invalidate(&self) {\n        tracing::warn!(\"invalidate invoked on a dead surface\")\n    }\n\n    fn invalidate_rect(&self, _rect: kurbo::Rect) {\n        tracing::warn!(\"invalidate_rect invoked on a dead surface\")\n    }\n\n    fn run_idle(&self) {\n        tracing::warn!(\"run_idle invoked on a dead surface\")\n    }\n","sourceCodeStart":644,"sourceCodeEnd":680,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/backend/wayland/surfaces/surface.rs#L644-L680","documentation":"druid-shell's dead-surface placeholder implementation panics for operations that make no sense on a dead surface. get_idle_handle is called to obtain an idle-notification handle; on a dead (closed/placeholder) surface there is no such handle, so the library panics unconditionally. Calling window/idle APIs on an already-destroyed surface is a programming error.","triggerScenarios":"Requesting an idle handle (idle::Handle) through a window whose underlying surface has been closed and replaced by the dead-surface placeholder implementation — i.e. any idle scheduling on a destroyed window.","commonSituations":"Scheduling idle callbacks from a background thread while the window is being closed; holding a WindowHandle past window destruction and then calling get_idle_handle; races between window teardown and async tasks that still reference the window.","solutions":["Do not retain WindowHandle beyond window destruction; drop or invalidate stored handles in the window-close handler (window_gone/close callbacks).","Check window liveness before scheduling idle work (query the handle's validity / catch the panic and treat the window as closed).","Route idle work through an application-level scheduler instead of a dead window's idle handle.","Use Arc<AtomicBool> or similar flags to cancel pending idle scheduling when the window closes."],"exampleFix":"// before: idle scheduled from a stale handle\nfn background_update(win: WindowHandle) {\n    let idle = win.get_idle_handle(); // panics if window closed\n    idle.schedule_idle(...);\n}\n\n// after: guard with a liveness flag\nfn background_update(win: WindowHandle, alive: Arc<AtomicBool>) {\n    if alive.load(Ordering::SeqCst) {\n        win.get_idle_handle().schedule_idle(...);\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Track window liveness yourself before using idle handles\nstruct TrackedWindow {\n    handle: WindowHandle,\n    alive: Arc<AtomicBool>,\n}\nfn can_schedule(w: &TrackedWindow) -> bool {\n    w.alive.load(Ordering::SeqCst)\n}","typeGuard":"fn is_alive(w: &TrackedWindow) -> bool {\n    w.alive.load(Ordering::SeqCst)\n}","tryCatchPattern":"let res = std::panic::catch_unwind(AssertUnwindSafe(|| win.get_idle_handle()));\nmatch res {\n    Ok(idle) => idle.schedule_idle(...),\n    Err(_) => { /* window closed; skip idle work */ }\n}","preventionTips":["Invalidate stored WindowHandles in the window-closed callback","Use an Arc<AtomicBool> liveness flag for all async/window-adjacent work","Avoid long-lived clones of WindowHandle in background tasks","Cancel pending idle scheduling during teardown"],"tags":["wayland","panic","dead-surface","idle-handle","lifecycle"],"backgroundTag":"unsupported-operation","analyzedSha":"0f8b1195e4e073f9597f2865299c3d18f8e4005f","analyzedAt":"2026-09-10T14:27:34.582Z","contentChangedAt":"2026-09-10T14:27:34.582Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}