slint-ui/slint · error

ShowPopupWindow is invoked on a sub-component

Error message

ShowPopupWindow is invoked on a sub-component

What it means

When generating C++ code for `show-popup-window` (and its `is-open` handling), the generator needs the current sub-component's class name to build a weak mapped handle for the popup's `is-open` setter. If `ctx.current_sub_component()` is None the generator panics: popup invocation is expected to be compiled within a sub-component context.

Solutions

  1. Ensure the ShowPopupWindow expression is compiled with an EvaluationContext created via `new_sub_component` for the containing sub-component
  2. If popups can now live at other levels, capture the enclosing component handle explicitly instead of expecting a sub-component
  3. Report with a reproducing .slint file if hit as a user

Example fix

// before
let self_ty = ident(&ctx.current_sub_component().expect("...").name);
// after
let self_ty = ident(&ctx.current_sub_component().unwrap_or_else(||
    panic!("ShowPopupWindow compiled outside sub-component context")).name);
Defensive patterns

Strategy: validation

Validate before calling

debug_assert!(ctx.current_sub_component().is_some(), "ShowPopupWindow requires a sub-component context");

Type guard

let self_component = ctx.current_sub_component().ok_or_else(||
    panic!("ShowPopupWindow compiled outside sub-component context"))?;

Prevention

When it happens

Trigger: A `ShowPopupWindow` expression is compiled while the EvaluationContext has no current sub-component — e.g. the popup call got moved into a global or root-level context by an earlier pass, or a new code path compiles popup expressions without `new_sub_component`.

Common situations: Slint compiler development: refactoring how popup expressions or `is-open` bindings are lowered; adding a new generator entry point that forgets to establish the sub-component frame.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@3a7e700487 (2026-09-16). Data as JSON: /api/errors/d78aabd350674cd1. Report an issue: GitHub.

Appendix: source

Thrown at internal/compiler/generator/cpp.rs:5381

                let popup_ctx = EvaluationContext::new_sub_component(
                    ctx.compilation_unit,
                    popup.item_tree.root,
                    CppGeneratorContext { global_access: "self->globals".into(), conditional_includes: ctx.generator_state.conditional_includes },
                    Some(&parent_ctx),
                );
                let position = compile_expression(&popup.position.borrow(), &popup_ctx);
                let close_policy = compile_expression(close_policy, ctx);
                let window_kind = if popup.is_tooltip { "slint::cbindgen_private::WindowKind::ToolTip" } else { "slint::cbindgen_private::WindowKind::Popup" };
                // Keep the parent's `is-open` property in sync. The setter is passed directly into
                // `show_popup`, so there is no extra registration call and no second popup lookup. The
                // `false` is delivered when the popup is dropped, which may be long after this frame, so
                // we cannot capture a raw `self`. We capture a weak *mapped* handle to the current
                // component instance -- the C++ equivalent of Rust's `self_weak`, which for a
                // sub-component points at that sub-component itself rather than at the enclosing item
                // tree (`self->self_weak`). Popups without `is-open` get a no-op setter.
                let is_open_setter = match is_open_args.first() {
                    Some(llr::Expression::PropertyReference(is_open_ref)) => {
                        let self_ty = ident(&ctx.current_sub_component().expect("ShowPopupWindow is invoked on a sub-component").name);
                        let set_is_open = access_member(is_open_ref, ctx).then(|p| format!("{p}.set(is_open)"));
                        format!(
                            "[weak = vtable::VWeakMapped<slint::private_api::ItemTreeVTable, const {self_ty}>( \
                                    vtable::VRcMapped<slint::private_api::ItemTreeVTable, const {self_ty}>(self->self_weak.lock().value(), self))] \
                             (bool is_open) {{ \
                                auto rc = weak.lock(); \
                                if (!rc) return; \
                                [[maybe_unused]] auto self = &**rc; \
                                {set_is_open}; \
                            }}"
                        )
                    }
                    _ => "[](bool) {}".to_string(),
                };
                item_owner(anchor_ref).then_named("anchor_owner", |owner| {
                    let (_, parent_component) = native_item_from_owner(anchor_ref, ctx, owner);
                    component_access.then(|component_access| {
                    let compo_ptr = if compo_path.is_empty() {

View on GitHub (pinned to 3a7e700487)