Textualize/textual · warning · NoHandler
No handler for {event_name!r}
Error message
No handler for {event_name!r} What it means
extract_handler_actions inspects a method's metadata (keys starting with '@' registered by the @on decorator) to find a handler matching an event path like ('Notification', 'Show'). If no metadata entry matches the event being brokered, it raises NoHandler. Internally this is often caught by _broker_event to skip the method, but when called directly it signals the method has no @on decorator for that event.
Source
Thrown at src/textual/_event_broker.py:37
Args:
event_name: Event to check from.
meta: Meta information (stored in Rich Style)
Raises:
NoHandler: If no handler is found.
Returns:
Action information.
"""
event_path = event_name.split(".")
for key, value in meta.items():
if key.startswith("@"):
name_args = key[1:].split(".")
if name_args[: len(event_path)] == event_path:
modifiers = name_args[len(event_path) :]
return HandlerArguments(set(modifiers), value)
raise NoHandler(f"No handler for {event_name!r}")
View on GitHub (pinned to 06dbeef4bb)
Solutions
- Decorate the target method with @on matching the event class, e.g. @on(NotificationShow)
- Verify the event_path passed matches the decorated event, including any modifiers after the '.'
- Use widget.post_message/standard dispatch instead of calling extract_handler_actions directly
- Catch NoHandler when iterating candidate methods, mirroring _broker_event
Example fix
# before
def handle(self, event) -> None: ...
extract_handler_actions(handle, ('Notification', 'Show')) # NoHandler
# after
from textual import on
@on(NotificationShow)
def handle(self, event) -> None: ...
extract_handler_actions(handle, ('Notification', 'Show')) Defensive patterns
Strategy: try-catch
Validate before calling
from textual import on
def has_handler_for(method, event_cls) -> bool:
for meta_key in getattr(method, '__textual_on', {}) or {}:
if meta_key.lstrip('@').split('.')[:1] == [event_cls.__name__]:
return True
return False Try / catch
from textual._event_broker import NoHandler
try:
args = extract_handler_actions(method, event_path)
except NoHandler:
args = None # skip this method, not a handler for the event Prevention
- Always decorate handlers with @on(EventClass) before extraction
- Prefer widget.post_message and Textual's built-in dispatch over the private broker API
- Keep the event_path aligned with the @on decorated event name
When it happens
Trigger: Calling extract_handler_actions(method, event_path) on a plain method or a method decorated with @on for a different event; e.g. extracting handlers for ('Notification','Show') from a method decorated @on(Button.Pressed).
Common situations: Direct use of the private _event_broker API in tests or custom dispatch loops; decorators missing or applied to the wrong event after refactoring; stale metadata after editing @on arguments.
Related errors
- Can't encode {datum!r}
- must be bytes
- Multiple handlers for key press {key_name!r}.\nWe found both
- The message class must have a 'control' to match with the on
- The attribute {attribute!r} can't be matched; have you added
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/0451ec3860fcf791.
Report an issue: GitHub.