{"record":{"id":"0281c97d2904c336","repo":"linebender/druid","slug":"application-state-already-borrowed","errorCode":null,"errorMessage":"Application state already borrowed","messagePattern":"Application state already borrowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-shell/src/application.rs","lineNumber":135,"sourceCode":"    /// Start the `Application` runloop.\n    ///\n    /// The provided `handler` will be used to inform of events.\n    ///\n    /// This will consume the `Application` and block the current thread\n    /// until the `Application` has finished executing.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the `Application` is already running.\n    pub fn run(self, handler: Option<Box<dyn AppHandler>>) {\n        // Make sure this application hasn't run() yet.\n        if let Ok(mut state) = self.state.try_borrow_mut() {\n            if state.running {\n                panic!(\"Application is already running\");\n            }\n            state.running = true;\n        } else {\n            panic!(\"Application state already borrowed\");\n        }\n\n        // Run the platform application\n        self.backend_app.run(handler);\n\n        // This application is no longer active, so clear the global reference\n        GLOBAL_APP.with(|global_app| {\n            *global_app.borrow_mut() = None;\n        });\n        // .. and release the main thread\n        util::release_main_thread();\n        // .. and mark as done so a new sequence can start\n        APPLICATION_CREATED\n            .compare_exchange(true, false, Ordering::AcqRel, Ordering::Acquire)\n            .expect(\"Application marked as not created while still running.\");\n    }\n\n    /// Quit the `Application`.","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-shell/src/application.rs#L117-L153","documentation":"`Application::run` stores its state in a `RefCell`. If `try_borrow_mut` fails, the state is already mutably borrowed (i.e. `run` is being re-entered or the state is borrowed elsewhere), so it panics to avoid aliased mutation of the application state.","triggerScenarios":"Re-entrant call to `run` (directly or via a handler while the first `run` is still on the stack), or some other code holding a mutable borrow of the application's internal state cell.","commonSituations":"Calling `run` from within an event handler or a callback triggered by the running loop; accidentally re-entering `run` through recursion.","solutions":["Never call `Application::run` from inside an app handler or callback; let the outer `run` continue","Ensure no code path borrows the application state while `run` executes","Keep `run` on the main entry path and drive logic via the event loop/handler instead"],"exampleFix":"// before\nfn on_command(&mut self, ...) {\n    self.app.run(None); // re-entrant borrow -> panic\n}\n\n// after\nfn on_command(&mut self, ...) {\n    // handle logic via events; the outer run() loop keeps running\n}","handlingStrategy":"try-catch","validationCode":"// Only call run from the top-level main function, never from handlers/callbacks","typeGuard":null,"tryCatchPattern":"std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| app.run(handler)));\n// Prefer prevention: do not call run re-entrantly.","preventionTips":["Never call `run` inside event handlers or callbacks","Avoid holding borrows of application state across the run call","Keep application lifecycle single-threaded and re-entrancy-free"],"tags":["panic","reentrancy","refcell","druid-shell"],"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"}