slint-ui/slint · error · RuntimeError

Callback '{name}' cannot be used with a callback decorator f

Error message

Callback '{name}' cannot be used with a callback decorator for an async function, as it doesn't return void

What it means

Component-level async callbacks must be declared void for the same reason as the global case: the coroutine return value cannot be handed back to Slint's synchronous callback invocation. If compdef.callback_returns_void(name) returns False (callback declared with a return type), constructing the subclass raises this RuntimeError.

Source

Thrown at api/python/slint/slint/__init__.py:192

                        is_void = compdef.global_callback_returns_void(
                            global_name, name
                        )
                        if is_void is None:
                            raise AttributeError(
                                f"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component"
                            )
                        if not is_void:
                            raise RuntimeError(
                                f"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it doesn't return void"
                            )
                    else:
                        is_void = compdef.callback_returns_void(name)
                        if is_void is None:
                            raise AttributeError(
                                f"Callback '{name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component"
                            )
                        if not is_void:
                            raise RuntimeError(
                                f"Callback '{name}' cannot be used with a callback decorator for an async function, as it doesn't return void"
                            )

                def mk_callback(
                    self: Any, callback: typing.Callable[..., Any]
                ) -> typing.Callable[..., Any]:
                    def invoke(*args: Any, **kwargs: Any) -> Any:
                        return callback(self, *args, **kwargs)

                    return invoke

                if "global_name" in callback_info:
                    self.__instance__.set_global_callback(
                        callback_info["global_name"], name, mk_callback(self, value)
                    )
                else:
                    self.__instance__.set_callback(name, mk_callback(self, value))

View on GitHub (pinned to a9ea814a58)

Solutions

  1. Declare the callback without a return type: `callback lookup(key: string);` and reload the file.
  2. Return data through a property or by invoking a Slint function from the coroutine when the result is ready.
  3. Keep the handler synchronous if the callback genuinely must return a value to Slint expressions.

Example fix

// before
export component App {
    callback load(int) -> [string] ;
}

@slint.callback
async def load(self, id): ...  # RuntimeError at instantiation

// after
export component App {
    callback load(int);                 // async = fire-and-forget
    out property <[string]> items;
}

@slint.callback
async def load(self, id):
    self.items = await fetch_items(id)
Defensive patterns

Strategy: validation

Validate before calling

# Lint: component-level async callbacks must be declared without `->`
import re
src = open("app.slint").read()
for m in re.finditer(r"callback\s+(\w+)\s*\([^)]*\)\s*->", src):
    if m.group(1) in my_async_callback_names:
        raise SystemExit(f"callback '{m.group(1)}' must be void (no '->') to use an async handler")

Try / catch

try:
    app = App()
except RuntimeError as e:
    if "doesn't return void" in str(e):
        raise SystemExit("Async callbacks must be declared void; deliver results via properties instead") from e
    raise

Prevention

When it happens

Trigger: `callback lookup(key: string) -> string;` on the component plus `@slint.callback` + `async def lookup(self, key)` in Python; raised when the subclass instance is created, before the callback is ever invoked.

Common situations: Making an existing returning callback async without changing its declaration; mixing awaitable I/O with synchronous data binding; code migrated from sync handlers that kept `-> T`.

Related errors


AI-assisted analysis of slint-ui/slint@a9ea814a58 (2026-08-16). Data as JSON: /api/errors/83cbedcecbad4e40. Report an issue: GitHub.