Textualize/textual · error · ReactiveError

Unable to bind non-reactive attribute {name!r} on {self}

Error message

Unable to bind non-reactive attribute {name!r} on {self}

What it means

DOMNode.data_bind raises ReactiveError when binding a name that is not a reactive attribute on self — data binding requires the target (self) to declare a reactive with that name so incoming changes can be stored and watched.

Source

Thrown at src/textual/dom.py:335

                yield WorldClock("Asia/Tokyo").data_bind(WorldClockApp.time)
            ```

        Raises:
            ReactiveError: If the data wasn't bound.

        Returns:
            Self.
        """
        _rich_traceback_omit = True

        parent = active_message_pump.get()

        if self._reactive_connect is None:
            self._reactive_connect = {}
        bind_vars = {**{reactive.name: reactive for reactive in reactives}, **bind_vars}
        for name, reactive in bind_vars.items():
            if name not in self._reactives:
                raise ReactiveError(
                    f"Unable to bind non-reactive attribute {name!r} on {self}"
                )
            if isinstance(reactive, Reactive) and not isinstance(
                parent, reactive.owner
            ):
                raise ReactiveError(
                    f"Unable to bind data; {reactive.owner.__name__} is not defined on {parent.__class__.__name__}."
                )
            self._reactive_connect[name] = (parent, reactive)
        if self._is_mounted:
            self._initialize_data_bind()
        else:
            self.call_later(self._initialize_data_bind)
        return self

    def _initialize_data_bind(self) -> None:
        """initialize a data binding.

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Declare a reactive with the same name on the binding widget: count: reactive[int] = reactive(0)
  2. Or bind to a different mechanism (e.g. watch methods / messages) if the widget shouldn't own state
  3. Ensure names match exactly between the parent reactive and the widget reactive

Example fix

# before
class MyWidget(Widget):
    def compose(self):
        yield Label().data_bind(MyApp.status)  # no 'status' reactive on Label
# after
class MyWidget(Widget):
    status: reactive[str] = reactive("")
    def compose(self):
        yield Label().data_bind(MyWidget.status)
Defensive patterns

Strategy: validation

Validate before calling

class MyWidget(Widget):
    status: reactive[str] = reactive("")  # declare before data_bind(MyApp.status)

Type guard

from textual.reactive import reactive

def can_bind(node, name: str) -> bool:
    return name in node._reactives

Try / catch

from textual.reactive import ReactiveError
try:
    child.data_bind(MyApp.status)
except ReactiveError as e:
    log.warning(str(e))

Prevention

When it happens

Trigger: widget.data_bind(SomeApp.field) where the widget has no reactive named 'field'; binding to a plain attribute or property; binding to a reactive defined only on the parent/app, not on the binding widget.

Common situations: Using @on/data_bind for app-to-widget sync but forgetting to declare the matching reactive on the widget; renaming the app reactive without updating widget declarations.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/65f68983935fab19. Report an issue: GitHub.