slint-ui/slint · error

Cannot set callback

Error message

Cannot set callback {global_name}::{name}: {e}

What it means

LiveComponent::set_global_callback panics when the interpreter cannot install a callback on the named global singleton. The callback is cached for hot-reload replay first; a failed registration (unknown global or callback name) panics because the live preview cannot function with missing handlers.

Solutions

  1. Confirm both the global is exported and the callback is declared on that global in the .slint file
  2. Use set_callback for callbacks declared on the component root instead
  3. Re-register all cached callbacks after each live-reload, tolerating removed ones

Example fix

// before
live.set_global_callback("Logic", "on_button_clik", |args| Value::Void); // typo
// after
live.set_global_callback("Logic", "on_button_click", |args| Value::Void);
Defensive patterns

Strategy: validation

Validate before calling

fn has_global_callback(def: &slint_interpreter::ComponentDefinition, g: &str, cb: &str) -> bool {
    def.globals().iter().any(|g2| g2.name == g) // plus property/callback inspection on that global
}

Try / catch

// panic! is not catchable; validate the global and callback name first
if is_exported_global("Logic") && declares_callback("Logic", "on_button_click") {
    live.set_global_callback("Logic", "on_button_click", |args| Value::Void);
}

Prevention

When it happens

Trigger: set_global_callback with a global_name that is not an exported global or a callback name not declared in that global.

Common situations: Typo in global or callback name; the callback is actually on the component root (use set_callback); globals changed during a hot-reload cycle before re-registration.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at internal/live-preview/live_component.rs:244

    /// Forward to invoke_global
    pub fn invoke_global(&self, global_name: &str, name: &str, args: &[Value]) -> Value {
        self.instance()
            .invoke_global(global_name, name, args)
            .unwrap_or_else(|e| panic!("Cannot invoke callback {global_name}::{name}: {e}"))
    }

    /// Forward to set_global_callback
    pub fn set_global_callback(
        &self,
        global_name: &str,
        name: &str,
        callback: Rc<dyn Fn(&[Value]) -> Value + 'static>,
    ) {
        self.callbacks.borrow_mut().insert(format!("{global_name}.{name}"), callback.clone());
        self.instance()
            .set_global_callback(global_name, name, move |args| callback(args))
            .unwrap_or_else(|e| panic!("Cannot set callback {global_name}::{name}: {e}"));
    }
}

enum WatcherState {
    Starting,
    /// The file system watcher notified the main thread of a change
    Changed,
    /// The main thread is waiting for the next event
    Waiting(Waker),
}

struct Watcher {
    // (wouldn't need to be an option if new_cyclic() could return errors)
    watcher: Option<FileWatcher>,
    state: WatcherState,
}

impl Watcher {

View on GitHub (pinned to 3a7e700487)