{"record":{"id":"9c9bb0c0929b3e00","repo":"linebender/druid","slug":"request-animation-frame-failed","errorCode":null,"errorMessage":"request_animation_frame failed","messagePattern":"request_animation_frame failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-shell/src/backend/web/window.rs","lineNumber":741,"sourceCode":"unsafe impl Sync for IdleHandle {}\n\nimpl IdleHandle {\n    /// Add an idle handler, which is called (once) when the main thread is idle.\n    pub fn add_idle_callback<F>(&self, callback: F)\n    where\n        F: FnOnce(&mut dyn WinHandler) + Send + 'static,\n    {\n        let mut queue = self.queue.lock().expect(\"IdleHandle::add_idle queue\");\n        queue.push(IdleKind::Callback(Box::new(callback)));\n\n        if queue.len() == 1 {\n            if let Some(window_state) = self.state.upgrade() {\n                let state = window_state.clone();\n                window_state\n                    .request_animation_frame(move || {\n                        state.process_idle_queue();\n                    })\n                    .expect(\"request_animation_frame failed\");\n            }\n        }\n    }\n\n    pub fn add_idle_token(&self, token: IdleToken) {\n        let mut queue = self.queue.lock().expect(\"IdleHandle::add_idle queue\");\n        queue.push(IdleKind::Token(token));\n\n        if queue.len() == 1 {\n            if let Some(window_state) = self.state.upgrade() {\n                let state = window_state.clone();\n                window_state\n                    .request_animation_frame(move || {\n                        state.process_idle_queue();\n                    })\n                    .expect(\"request_animation_frame failed\");\n            }\n        }","sourceCodeStart":723,"sourceCodeEnd":759,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/backend/web/window.rs#L723-L759","documentation":"Panic from `.expect()` when `IdleHandle::wake` (or the equivalent idle-notification path) fails to schedule `process_idle_queue` via `request_animation_frame`. Idle tokens are flushed on the next animation frame; if the browser rejects the rAF registration, queued idle work would be silently lost, so the library treats it as fatal.","triggerScenarios":"`IdleHandle::wake` / `schedule_idle` on the web backend after the window has been dropped (the `upgrade()` still succeeds but the page is torn down), during page unload, or in an environment lacking `requestAnimationFrame`.","commonSituations":"A background task (fetch promise, WebSocket message) resolves and calls `schedule_idle` after the user navigated away or closed the tab; running wasm under Node/jsdom tests; detached iframes receiving late idle wake-ups.","solutions":["Drop/cancel IdleHandles and background tasks when the window closes instead of waking a dead window","Make background completions check page/window liveness (e.g. `web_sys::window().is_some()`) before scheduling idle work","Add a requestAnimationFrame polyfill for non-browser test environments","Debounce wake-ups so many late callbacks don't pile up on a torn-down page"],"exampleFix":"// before\nhandle.wake(); // panics if page unloaded\n// after\nif web_sys::window().is_some() {\n    handle.wake();\n}","handlingStrategy":"fallback","validationCode":"// Confirm browser context before waking idle handles\nfn safe_to_wake() -> bool {\n    web_sys::window().is_some()\n}","typeGuard":"fn handle_live(handle: &IdleHandle) -> bool {\n    !handle_window_closed && web_sys::window().is_some()\n}","tryCatchPattern":"// Fallback: retry once on the next tick, else log and drop\nif safe_to_wake() {\n    handle.wake();\n} else {\n    console_error(\"idle wake dropped: no window context\");\n}","preventionTips":["Cancel or drop IdleHandles on window close/navigation","Route all background completions through a liveness-checked scheduler","Use requestIdleCallback/rAF polyfills in tests","Debounce idle wake-ups to reduce late callbacks on torn-down pages"],"tags":["web","wasm","idle","request-animation-frame"],"backgroundTag":"request-animation-frame-failed","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"}