Textualize/textual · error · NoScreen
node has no screen
Error message
node has no screen
What it means
NoScreen is raised by the screen property when the node has no Screen ancestor: the widget is not mounted on a running app/screen, so no screen can be resolved by walking _parent links.
Source
Thrown at src/textual/dom.py:806
A screen object.
Raises:
NoScreen: If this node isn't mounted (and has no screen).
"""
# Get the node by looking up a chain of parents
# Note that self.screen may not be the same as self.app.screen
from textual.screen import Screen
node: MessagePump | None = self
try:
while node is not None and not isinstance(node, Screen):
node = node._parent
except AttributeError:
raise RuntimeError(
"Widget is missing attributes; have you called the constructor in your widget class?"
) from None
if not isinstance(node, Screen):
raise NoScreen("node has no screen")
return node
@property
def id(self) -> str | None:
"""The ID of this node, or None if the node has no ID."""
return self._id
@id.setter
def id(self, new_id: str) -> str:
"""Sets the ID (may only be done once).
Args:
new_id: ID for this node.
Raises:
ValueError: If the ID has already been set.
"""
check_identifiers("id", new_id)View on GitHub (pinned to 06dbeef4bb)
Solutions
- Move code that needs self.screen out of __init__ into on_mount or a lifecycle hook that runs after mounting
- In tests, use textual's run_test() async context / Pilot so widgets are mounted on a screen
- If the widget may be detached, check for a screen defensively before use
Example fix
# before
class MyWidget(Widget):
def __init__(self):
super().__init__()
self.bg = self.screen.background # NoScreen
# after
class MyWidget(Widget):
def on_mount(self) -> None:
self.bg = self.screen.background Defensive patterns
Strategy: validation
Validate before calling
def safe_screen(widget):
node = widget
while node is not None and not isinstance(node, Screen):
node = node._parent
return node # None if not mounted
scr = safe_screen(widget)
if scr is None:
defer_work_until_mount() Type guard
from textual.screen import Screen
def is_mounted(widget) -> bool:
return widget.screen is not None if widget.is_mounted else False Try / catch
from textual.screen import NoScreen
try:
scr = widget.screen
except NoScreen:
schedule_after_mount(widget) # retry later Prevention
- Never access self.screen in __init__ or compose
- Use on_mount for screen-dependent logic
- Use run_test()/Pilot in tests so screens exist
When it happens
Trigger: Accessing widget.screen (or APIs that use it: screen.refresh, posting to screen, styles resolution) before the widget is mounted, e.g. inside __init__ or compose() before the widget is attached to a Screen.
Common situations: Calling self.screen in a widget constructor or in compose(); using widgets standalone in unit tests without an app runner; accessing a removed widget after remove() breaks the parent chain.
Related errors
- Tried to insert a widget with ID {widget_id!r}, but a widget
- App is not running
- Can't remove active mode {mode!r}
- Can't await screen.dismiss() from the screen's message handl
- Can't make {self} active as it is not in the current stack.
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/370724d88a72f608.
Report an issue: GitHub.