{"record":{"id":"74bcf59a4c3e3bde","repo":"emilk/egui","slug":"context-root-ui-was-called-while-the-root-ui-was-already","errorCode":null,"errorMessage":"Context::root_ui was called while the root Ui was already borrowed. You are probably calling it from within `Context::run_ui` or `Context::root_ui`. Use the `&mut Ui` you were given instead.","messagePattern":"Context::root_ui was called while the root Ui was already borrowed\\. You are probably calling it from within `Context::run_ui` or `Context::root_ui`\\. Use the `&mut Ui` you were given instead\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/egui/src/context.rs","lineNumber":1000,"sourceCode":"\n    /// Take the root [`Ui`] out of the viewport state, creating it if needed.\n    ///\n    /// The [`Ui`] must be put back with [`RootUi::Available`] when done,\n    /// so that the next call to [`Self::root_ui`] can find it.\n    fn take_root_ui(&self) -> Ui {\n        let root_ui =\n            self.write(|ctx| core::mem::replace(&mut ctx.viewport().root_ui, RootUi::Borrowed));\n        match root_ui {\n            RootUi::Available(root_ui) => root_ui,\n            RootUi::Pending => Ui::new(\n                self.clone(),\n                self.viewport_id().root_ui_id(),\n                UiBuilder::new()\n                    .layer_id(LayerId::background())\n                    .max_rect(self.viewport_rect()),\n            ),\n            RootUi::Borrowed => {\n                panic!(\n                    \"Context::root_ui was called while the root Ui was already borrowed. \\\n                     You are probably calling it from within `Context::run_ui` or `Context::root_ui`. \\\n                     Use the `&mut Ui` you were given instead.\"\n                );\n            }\n        }\n    }\n\n    /// Drop the root [`Ui`] of the current pass, if any,\n    /// remembering how much of it was used.\n    ///\n    /// Called at the end of each pass.\n    fn finish_root_ui(&self) {\n        let root_ui = self.write(|ctx| core::mem::take(&mut ctx.viewport().root_ui));\n        match root_ui {\n            RootUi::Pending => {}\n            RootUi::Available(root_ui) => {\n                self.pass_state_mut(|state| {","sourceCodeStart":982,"sourceCodeEnd":1018,"githubUrl":"https://github.com/emilk/egui/blob/8fb03c9ae9a6bf1ffa602dfba51ed575f2655975/crates/egui/src/context.rs#L982-L1018","documentation":"egui's Context only allows one borrow of the root Ui at a time. `Context::root_ui()` panics when the root Ui is already checked out — typically because you are inside a `Context::run_ui` (or a previous `root_ui`) closure that already handed you an `&mut Ui`. The library deliberately panics (RootUi::Borrowed) instead of returning an error because this is an API-usage invariant violation.","triggerScenarios":"Calling `ctx.root_ui(...)` while a previous `root_ui` call is still active, or calling it from inside the closure passed to `Context::run_ui` / `run_ui`-style methods where an `&mut Ui` was already provided. Also caused by holding the `&mut Ui` from a first `root_ui()` call while making a nested second call.","commonSituations":"Migrating code from older egui versions that allowed `ctx.root_ui()` anywhere (e.g. inside `Update` callbacks or widget code) to newer versions with a borrow-tracked root Ui; wrapping legacy immediate-mode drawing code in a `run_ui` closure and then calling `ctx.root_ui()` inside it; nesting `root_ui` calls in helper functions that each grab the root Ui.","solutions":["Use the `&mut Ui` already passed to your closure (from `run_ui` or the outer `root_ui` call) instead of calling `ctx.root_ui()` again","Restructure so nested widget code takes `ui: &mut Ui` as a parameter rather than re-acquiring the root Ui from the Context","Ensure the previous `root_ui()`/`run_ui` call has fully returned (drop its guard) before calling `root_ui` again on the same context","Split code that needs a fresh Ui into a separate pass outside the active borrow"],"exampleFix":"// before\nctx.run_ui(ctx.screen_rect(), |ctx| {\n    ctx.root_ui().add(egui::Label::new(\"hello\")); // panics: root Ui already borrowed\n});\n// after\nctx.run_ui(ctx.screen_rect(), |ctx| {\n    let mut ui = ctx.root_ui(); // borrow once\n    ui.add(egui::Label::new(\"hello\"));\n});\n// or inside a run_ui closure with a provided ui:\nctx.run_ui(ctx.screen_rect(), |_ctx, ui| {\n    ui.add(egui::Label::new(\"hello\")); // use the given &mut Ui\n});","handlingStrategy":"type-guard","validationCode":"// Track whether a root Ui borrow is already active in this call path.\n// Prefer passing `&mut Ui` down instead of calling ctx.root_ui() in helpers:\nfn draw_panel(ui: &mut Ui) {\n    // use ui, never ctx.root_ui() here\n    ui.label(\"panel\");\n}\n// Call it as: draw_panel(&mut ui) inside run_ui/root_ui scope.","typeGuard":"fn can_call_root_ui(borrow_active: bool) -> bool { !borrow_active } // only call ctx.root_ui() when no enclosing run_ui/root_ui scope is active","tryCatchPattern":null,"preventionTips":["Never call ctx.root_ui() inside a run_ui/root_ui closure; use the provided &mut Ui","Pass `&mut Ui` down to helper functions instead of the Context","Keep root_ui()/run_ui scopes short and non-overlapping; do not store the returned Ui beyond the closure","Audit UI helper code when upgrading egui versions, since older APIs allowed unrestricted ctx.root_ui() calls"],"tags":["egui","gui","borrow-checker","immediate-mode","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8fb03c9ae9a6bf1ffa602dfba51ed575f2655975","analyzedAt":"2026-09-19T15:06:50.907Z","contentChangedAt":"2026-09-19T15:06:50.907Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}