{"record":{"id":"40649dd4d0f62651","repo":"linebender/druid","slug":"unexpected-wayland-event-evt","errorCode":null,"errorMessage":"unexpected wayland event: {evt:?}","messagePattern":"unexpected wayland event: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-shell/src/backend/wayland/application.rs","lineNumber":446,"sourceCode":"    fn zwlr_layershell_v1(&self) -> Option<wl::Main<ZwlrLayerShellV1>> {\n        self.zwlr_layershell_v1.clone()\n    }\n}\n\nimpl Data {\n    pub(crate) fn set_cursor(&self, cursor: &mouse::Cursor) {\n        self.pointer.replace(cursor);\n    }\n\n    /// Send all pending messages and process all received messages.\n    ///\n    /// Don't use this once the event loop has started.\n    pub(crate) fn sync(&self) -> Result<(), Error> {\n        self.wayland\n            .queue\n            .borrow_mut()\n            .sync_roundtrip(&mut (), |evt, _, _| {\n                panic!(\"unexpected wayland event: {evt:?}\")\n            })\n            .map_err(Error::fatal)?;\n        Ok(())\n    }\n\n    fn current_window_id(&self) -> u64 {\n        static DEFAULT: u64 = 0_u64;\n        *self.active_surface_id.borrow().front().unwrap_or(&DEFAULT)\n    }\n\n    pub(super) fn acquire_current_window(&self) -> Option<WindowHandle> {\n        self.handles\n            .borrow()\n            .get(&self.current_window_id())\n            .cloned()\n    }\n\n    fn handle_timer_event(&self, _token: TimerToken) {","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/backend/wayland/application.rs#L428-L464","documentation":"During `sync()`'s roundtrip, the Wayland connection expects only reply events, but the server sent an unexpected event before the roundtrip finished. Because pre-loop events cannot be routed to a window, the code panics rather than dropping them silently.","triggerScenarios":"Calling `sync()` after the event loop has started (its documented precondition), or the compositor dispatching an unhandled event type during a `sync_roundtrip` callback.","commonSituations":"Calling `Application::sync` at runtime after `run` started the loop; compositor quirks sending events during the initial roundtrip.","solutions":["Only call `sync()` during setup, before the event loop starts","Route events through the running loop's dispatcher after startup instead of syncing","Update wayland-backend/compositor handling if a legit new event type arrives; patch the panic to log-and-ignore"],"exampleFix":"// before\nlet app = Application::new()?;\napp.run(None);\napp.sync()?; // loop already running\n\n// after\nlet app = Application::new()?;\napp.sync()?; // before run\napp.run(None);","handlingStrategy":"validation","validationCode":"// Guard sync behind a lifecycle check in caller code:\nif !event_loop_started { app.sync()?; }","typeGuard":"fn sync_allowed(loop_started: bool) -> bool { !loop_started }","tryCatchPattern":null,"preventionTips":["Call `sync()` only during initialization, before `run()`","Use the running loop's event dispatch instead of sync after startup","Wrap sync in setup-only code paths guarded by lifecycle flags"],"tags":["wayland","event-loop","panic","linux"],"backgroundTag":"invalid-state-transition","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"}