Universal-Debloater-Alliance/universal-android-debloater-next-generation · error
Layout must have at least 1 child
Error message
Layout must have at least 1 child
What it means
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.
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
Example fix
// before
let content_bounds = layout
.children()
.next()
.expect("Layout must have at least 1 child")
.bounds();
// after
if let Some(child) = layout.children().next() {
let content_bounds = child.bounds();
if !content_bounds.contains(cursor_position) {
shell.publish(message.clone());
return;
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if layout.children().next().is_none() {
// no content laid out yet; skip outside-click handling
return;
} Type guard
fn first_child<'a>(layout: &Layout<'a>) -> Option<&'a crate::widgets::modal::Child> {
layout.children().next()
} Try / catch
// Use iterator combinator instead of expect: let content_bounds = layout.children().next().map(|c| c.bounds());
Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- removal recommendation must be selected
- User must be selected
- {e}
- There must be 1 tab after serial
- Could not write config file to disk!
AI-assisted analysis of Universal-Debloater-Alliance/universal-android-debloater-next-generation@64465c850c (2026-09-12).
Data as JSON: /api/errors/8a20e0ca66d0de86.
Report an issue: GitHub.
Appendix: source
Thrown at crates/uad-gui/src/widgets/modal.rs:206
&mut self,
event: &Event,
layout: Layout<'_>,
cursor: Cursor,
renderer: &Renderer,
clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>,
) {
if let Some(message) = self.on_blur.as_ref()
&& matches!(
event,
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
)
&& let Some(cursor_position) = cursor.position()
{
let content_bounds = layout
.children()
.next()
.expect("Layout must have at least 1 child")
.bounds();
if !content_bounds.contains(cursor_position) {
shell.publish(message.clone());
return;
}
}
self.content.as_widget_mut().update(
self.tree,
event,
layout.children().next().unwrap(),
cursor,
renderer,
clipboard,
shell,
&self.viewport,
);
}View on GitHub (pinned to 64465c850c)