slint-ui/slint · error

constraint must have binding

Error message

constraint must have binding

What it means

This panic fires in `merge_explicit_constraints` (internal/compiler/passes/default_geometry.rs:345), called from `gen_layout_info_prop` while generating layout info for elements with explicit layout constraints. For each restriction the code fetches the element's binding for the constraint property (e.g. `min-width`, `preferred-height`) and asserts a binding exists. A missing binding means a constraint was registered in the layout analysis without an actual property binding — an inconsistent compiler state.

Solutions

  1. Set explicit layout constraints directly with property bindings (e.g. `min-width: 100px;`) rather than via intermediate indirections.
  2. Test with the latest stable Slint compiler to rule out a regression; downgrade if a nightly fails.
  3. Simplify the layout — split deeply nested or unusually constrained layouts into sub-components.
  4. Contributors: verify `register_property_with_let`/constraint registration always creates a binding before `merge_explicit_constraints` reads it.

Example fix

// before
Rectangle { width: parent.width * 0.5; } // implicit, no constraint binding
// after
Rectangle { min-width: 100px; preferred-width: 200px; }
Defensive patterns

Strategy: validation

Validate before calling

// Prefer real bindings for every constraint property you declare
fn constraints_have_bindings(element_props: &[&str]) -> bool {
    ["min-width", "min-height", "max-width", "max-height", "preferred-width", "preferred-height"]
        .iter().all(|c| !element_props.contains(c) || true /* verify a binding exists for each declared constraint */)
}

Prevention

When it happens

Trigger: Compiling a layout (Row/Column/GridLayout or a component with explicit min/max/preferred size constraints) where a restriction was recorded for an element/property pair whose binding was removed or never created — e.g. constraints set on elements without real bindings, bindings consumed/cleared by an earlier pass, or two-way binding edge cases.

Common situations: Nightly compiler regressions in default geometry; .slint layouts combining percentage/implicit sizes with explicit constraints in unusual ways; contributor changes to binding creation or constraint collection.

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/1fc39bcc41e02c3d. Report an issue: GitHub.

Appendix: source

Thrown at internal/compiler/passes/default_geometry.rs:349

                    p.clone(),
                    Expression::StructFieldAccess {
                        base: Expression::ReadLocalVariable {
                            name: unique_name.clone(),
                            ty: ty.clone(),
                        }
                        .into(),
                        name: p.clone(),
                    },
                )
            })
            .collect::<BTreeMap<_, _>>();

        for (nr, s) in constraints.for_each_restrictions(orientation) {
            let e = nr
                .element()
                .borrow()
                .binding(nr.name())
                .expect("constraint must have binding")
                .expression
                .clone();
            debug_assert!(!matches!(e, Expression::Invalid));
            values.insert(s.into(), e);
        }
        *expr = Expression::CodeBlock([store, Expression::Struct { ty: s.clone(), values }].into());
    }
}

fn explicit_layout_info(e: &ElementRc, orientation: Orientation) -> Expression {
    let mut values = BTreeMap::new();
    let (size, orient) = match orientation {
        Orientation::Horizontal => ("width", "horizontal"),
        Orientation::Vertical => ("height", "vertical"),
    };
    for (k, v) in [
        ("min", format_smolstr!("min-{size}")),
        ("max", format_smolstr!("max-{size}")),

View on GitHub (pinned to 3a7e700487)