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
- Declare a reactive with the same name on the binding widget: count: reactive[int] = reactive(0)
- Or bind to a different mechanism (e.g. watch methods / messages) if the widget shouldn't own state
- 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
- Declare a matching reactive on the binding widget for every data_bind name
- Keep parent and widget reactive names in sync when renaming
- Type-check binding targets in tests
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
- A Reactive class is required; for example: MyApp.theme
- Unable to bind data; {reactive.owner.__name__} is not define
- No nodes match {self!r} on {self.node!r}
- No nodes match {self!r} on dom{self.node!r}
- {name!r} is an invalid {description}; identifiers must conta
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/65f68983935fab19.
Report an issue: GitHub.