slint-ui/slint · error
there should be a popup menu if we want to show it
Error message
there should be a popup menu if we want to show it
What it means
When the C++ generator compiles the builtin `show-popup-menu` function, it expects `ctx.compilation_unit.popup_menu` to be `Some`. The compiler populates `popup_menu` exactly when a popup menu is used in the compilation unit, so a None here means the `show_popup_menu` builtin is being generated without the supporting popup-menu item tree having been registered.
Solutions
- Ensure the compilation pass that registers the popup menu item tree runs before C++ code generation
- Check that `compilation_unit.popup_menu` is populated whenever `show_popup_menu` appears in the expression set
- Replace the expect with a compile error diagnostic pointing at the missing popup menu declaration
Example fix
// before
let popup = ctx.compilation_unit.popup_menu.as_ref().expect("there should be a popup menu if we want to show it");
// after
let popup = ctx.compilation_unit.popup_menu.as_ref().unwrap_or_else(||
panic!("show_popup_menu called but no popup menu was registered in this compilation unit")); Defensive patterns
Strategy: validation
Validate before calling
if ctx.compilation_unit.popup_menu.is_none() {
panic!("show_popup_menu generated but no popup menu registered in this compilation unit");
} Type guard
let popup_menu = match ctx.compilation_unit.popup_menu.as_ref() {
Some(p) => p,
None => panic!("popup menu not registered; run the popup-menu collection pass first"),
}; Prevention
- Verify the popup-menu collection pass runs before all code generators
- Add an end-of-pipeline assertion: show_popup_menu usage implies popup_menu registered
- Cover popup-menu codegen in both C++ and Rust generator tests
- When adding tooling pipelines (LSP, preview), include the popup-menu registration pass
When it happens
Trigger: Compiling a call to `show-popup-menu` in a compilation unit where the `popup_menu` field was never set — e.g. the register_builtin_evaluation_functions/pass that collects the popup menu did not run or ran after codegen, or the popup menu declaration failed to register.
Common situations: Compiler development: changes to how `popup_menu` is collected on the CompilationUnit; partial compilation pipelines (LSP, live-preview) that skip the collection pass.
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
- ShowPopupWindow is invoked on a sub-component
- Expression::ObjectAccess: Cannot find a key in an object
- model two-way bindings only exist on sub-components
- there should be a popup menu if we want to show it
- Expression::StructFieldAccess: Cannot find a key in an…
AI-assisted analysis of slint-ui/slint@3a7e700487 (2026-09-16).
Data as JSON: /api/errors/b360d110e31320f7.
Report an issue: GitHub.
Appendix: source
Thrown at internal/compiler/generator/cpp.rs:5453
component_access.then(|component_access| format!("{component_access}->{compo_path}globals->window().window_handle().close_popup({component_access}->{compo_path}popup_id_{popup_index})"))
} else {
panic!("internal error: invalid args to ClosePopupWindow {arguments:?}")
}
}
BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {
let [llr::Expression::PropertyReference(context_menu_ref), entries, position] = arguments
else {
panic!("internal error: invalid args to ShowPopupMenu {arguments:?}")
};
let context_menu = access_member(context_menu_ref, ctx);
let position = compile_expression(position, ctx);
let popup = ctx
.compilation_unit
.popup_menu
.as_ref()
.expect("there should be a popup menu if we want to show it");
let popup_id = ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);
let window = access_window_field(ctx);
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 },
None,
);
let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();
let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();
let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();
let access_close = access_member(&popup.close, &popup_ctx).unwrap();
item_owner(context_menu_ref).then_named("context_menu_owner", |owner| {
let (_, context_menu_rc) = native_item_from_owner(context_menu_ref, ctx, owner);
let close_popup = context_menu.then(|context_menu| {
format!("{window}.close_popup({context_menu}.popup_id)")View on GitHub (pinned to 3a7e700487)