slint-ui/slint · error

binding was of the wrong type

Error message

binding was of the wrong type

What it means

In the non-animated `Rtti::set_binding` implementation, the user-supplied binding is evaluated and its `Value` result is converted with `try_into()` to the property's native type; a failed conversion is mapped to `Err(())` and then immediately unwrapped with `.expect("binding was of the wrong type")`. This panics when a binding set through the RTTI/dynamic-property API produces a Value that cannot be converted into the property element type T.

Solutions

  1. Make the binding closure return a `Value` whose type matches the property's declared type (use the property's default value as a template)
  2. Check the property's type via RTTI (`PropertyRtti::type_()`) before binding and construct the matching Value variant
  3. If types can vary at runtime, perform an explicit, graceful conversion inside the closure instead of relying on try_into

Example fix

// before
handle.set_binding(prop, || Value::String("42".into()), AnimatedBindingKind::NotAnimated);
// after
handle.set_binding(prop, || Value::Number(42.0), AnimatedBindingKind::NotAnimated);
Defensive patterns

Strategy: type-guard

Validate before calling

// check the property's declared type before binding
let prop_type = prop_rtti.ty();
let value_type = std::mem::discriminant(&value);
assert_eq!(value_type_matches(prop_type, &value), true);

Type guard

fn value_matches(prop_ty: ValueType, v: &Value) -> bool {
    matches!((prop_ty, v),
        (ValueType::Number, Value::Number) |
        (ValueType::String, Value::String) |
        (ValueType::Bool, Value::Bool) | /* ... */ )
}

Try / catch

// expect() panics, so use catch_unwind only as a last resort
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| handle.set_binding(prop, binding, kind)));

Prevention

When it happens

Trigger: Calling `set_binding` on a dynamically-accessed property (e.g. via the interpreter / `DynamicType` RTTI path) where the closure returns a `Value` of a different type than the property declared (e.g. assigning a string Value to an int property, or a length to a color).

Common situations: Interpreter/Node/Python/C++ FFI code setting properties with values of the wrong Slint type; property type changed in .slint markup without updating the binding code.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at internal/core/rtti.rs:260

    ) -> Result<(), ()> {
        if animation.is_some() {
            Err(())
        } else {
            self.apply_pin(item).set(value.try_into().map_err(|_| ())?);
            Ok(())
        }
    }
    fn set_binding(
        &self,
        item: Pin<&Item>,
        binding: Box<dyn Fn() -> Value>,
        animation: AnimatedBindingKind,
    ) -> Result<(), ()> {
        if !matches!(animation, AnimatedBindingKind::NotAnimated) {
            Err(())
        } else {
            self.apply_pin(item).set_binding(move || {
                binding().try_into().map_err(|_| ()).expect("binding was of the wrong type")
            });
            Ok(())
        }
    }
    fn offset(&self) -> usize {
        self.get_byte_offset()
    }

    #[cfg(slint_debug_property)]
    fn set_debug_name(&self, item: Pin<&Item>, name: alloc::string::String) {
        self.apply_pin(item).debug_name.replace(name);
    }

    #[allow(unsafe_code)]
    unsafe fn link_two_ways(&self, item: Pin<&Item>, property2: *const c_void) {
        let p1 = self.apply_pin(item);
        // Safety: that's the invariant of this function
        let p2 = unsafe { Pin::new_unchecked((property2 as *const Property<T>).as_ref().unwrap()) };

View on GitHub (pinned to 3a7e700487)