{"record":{"id":"8a20e0ca66d0de86","repo":"Universal-Debloater-Alliance/universal-android-debloater-next-generation","slug":"layout-must-have-at-least-1-child","errorCode":null,"errorMessage":"Layout must have at least 1 child","messagePattern":"Layout must have at least 1 child","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/uad-gui/src/widgets/modal.rs","lineNumber":206,"sourceCode":"        &mut self,\n        event: &Event,\n        layout: Layout<'_>,\n        cursor: Cursor,\n        renderer: &Renderer,\n        clipboard: &mut dyn Clipboard,\n        shell: &mut Shell<'_, Message>,\n    ) {\n        if let Some(message) = self.on_blur.as_ref()\n            && matches!(\n                event,\n                Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))\n            )\n            && let Some(cursor_position) = cursor.position()\n        {\n            let content_bounds = layout\n                .children()\n                .next()\n                .expect(\"Layout must have at least 1 child\")\n                .bounds();\n            if !content_bounds.contains(cursor_position) {\n                shell.publish(message.clone());\n                return;\n            }\n        }\n\n        self.content.as_widget_mut().update(\n            self.tree,\n            event,\n            layout.children().next().unwrap(),\n            cursor,\n            renderer,\n            clipboard,\n            shell,\n            &self.viewport,\n        );\n    }","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/64465c850c7ed36329e67165ac08501abffb218e/crates/uad-gui/src/widgets/modal.rs#L188-L224","documentation":"This is a Rust `Option::expect` panic inside a modal widget's `update` in `uad-gui` (Iced). The code asks the iced `Layout` for its first child via `layout.children().next().expect(\"Layout must have at least 1 child\")` to get the content bounds and check whether the cursor clicked outside the modal. The library/widget assumes the modal layout always renders at least one child; if the modal content is empty or not yet laid out, the iterator yields `None` and the app panics.","triggerScenarios":"A mouse/cursor press event is processed by the modal's `update` while the modal's layout has zero children — e.g. the modal content widget failed to build, was cleared, or the event fires before the first layout pass populates children.","commonSituations":"Rendering a modal with empty/conditional content that produced no children this frame; a click arriving during the same frame the modal opens before layout completes; a refactor that removes the modal's container/child for certain states; iced version changes altering layout child behavior.","solutions":["Replace `.expect(...)` with `if let Some(child) = layout.children().next() { let content_bounds = child.bounds(); ... }` so clicks outside without content just publish the close message","Ensure the modal always renders at least one child (e.g. a non-empty container) for every state where cursor handling is active","Gate the cursor-handling branch on the modal actually having content (a `is_open && content.is_some()` style condition)","Log/ignore clicks when children are empty instead of panicking, since a click on an empty modal should simply dismiss it"],"exampleFix":"// before\nlet content_bounds = layout\n    .children()\n    .next()\n    .expect(\"Layout must have at least 1 child\")\n    .bounds();\n// after\nif let Some(child) = layout.children().next() {\n    let content_bounds = child.bounds();\n    if !content_bounds.contains(cursor_position) {\n        shell.publish(message.clone());\n        return;\n    }\n}","handlingStrategy":"type-guard","validationCode":"if layout.children().next().is_none() {\n    // no content laid out yet; skip outside-click handling\n    return;\n}","typeGuard":"fn first_child<'a>(layout: &Layout<'a>) -> Option<&'a crate::widgets::modal::Child> {\n    layout.children().next()\n}","tryCatchPattern":"// Use iterator combinator instead of expect:\nlet content_bounds = layout.children().next().map(|c| c.bounds());","preventionTips":["Never .expect() on iterator .next(); use if let Some / map","Guarantee modal content renders at least one child in every reachable state","Handle cursor events only after the modal has completed a layout pass","Add a regression test that clicks a modal on its first frame"],"tags":["rust","panic","iced","layout","gui-widget"],"backgroundTag":"empty-required-field","analyzedSha":"64465c850c7ed36329e67165ac08501abffb218e","analyzedAt":"2026-09-12T09:09:23.137Z","contentChangedAt":"2026-09-12T09:09:23.137Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}