reflex-dev/reflex · error · ValueError
Unexpected event type, {type(e)}.
Error message
Unexpected event type, {type(e)}. What it means
While converting event specs (e.g. in _apply_handler or event chains), Reflex accepts EventSpec objects and zero-arg EventHandler calls; anything else — a raw function, lambda, string, or arbitrary object — triggers ValueError 'Unexpected event type'. The type of the offending object is included in the message.
Source
Thrown at packages/reflex-base/src/reflex_base/event/__init__.py:147
for e in events:
if callable(e) and getattr(e, "__name__", "") == "<lambda>":
# A lambda was returned, assume the user wants to call it with no args.
e = e()
if isinstance(e, Event):
# If the event is already an event, append it to the list.
if router_data is not None and e.router_data != router_data:
out.append(
dataclasses.replace(e, router_data=e.router_data | router_data)
)
else:
out.append(e)
continue
# Otherwise, create an event from the event spec.
if isinstance(e, EventHandler):
e = e()
if not isinstance(e, EventSpec):
msg = f"Unexpected event type, {type(e)}."
raise ValueError(msg)
name = format.format_event_handler(e.handler)
# Detach mutable values from any state-bound proxies (e.g.
# ImmutableMutableProxy from a background task's StateProxy),
# copying only subtrees that are actually proxied.
payload = {
k._js_expr: _detach_state_proxies(v._decode()) for k, v in e.args
}
# Create an event and append it to the list.
out.append(
Event(
name=name,
payload=payload,
router_data=router_data or {},
)
)
return outView on GitHub (pinned to 45b8ed5ab7)
Solutions
- Look at {type(e)} in the message to identify the offending value
- Wrap plain functions with rx.event / ensure you return EventSpec-producing calls (e.g. call the handler: State.my_handler())
- Don't return raw callables/strings from event handlers; map them to event specs first
Example fix
# before
def index():
return rx.button("Go", on_click=[State.go, do_something_raw])
# after
@rx.event
def do_something(): ...
def index():
return rx.button("Go", on_click=[State.go, do_something])
Defensive patterns
Strategy: type-guard
Validate before calling
from reflex_base.event import EventSpec, EventHandler
assert all(isinstance(e, (EventSpec, EventHandler)) for e in event_list), f"non-event in list: {[type(e) for e in event_list]}" Type guard
def is_event_like(e) -> bool:
from reflex_base.event import EventSpec, EventHandler
return isinstance(e, (EventSpec, EventHandler)) Try / catch
null
Prevention
- Always return rx.event-decorated callables' results from handlers
- Type event lists as list[EventSpec] in your own helpers so mypy catches raw callables
When it happens
Trigger: Returning or chaining values that aren't events from event handlers/compile targets: returning a plain function reference, a string, or None-adjacent objects where an EventSpec/EventHandler is expected (e.g. mixing rx.event results with raw callables in a list passed to event chaining).
Common situations: Forgetting to call an EventHandler, returning a lambda from a handler, or passing an unwrapped user function into an API expecting event specs.
Related errors
- `rx.EventHandler` parameters are only supported on component
- `children` in `{fn_name}` cannot be an `rx.EventHandler`; us
- `rx.EventHandler` parameter `{parameter.name}` in `{fn_name}
- reflex.Config.plugins must contain Plugin instances, but got
- Invalid plugin class: {plugin_name!r} for {field_name}. Must
AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28).
Data as JSON: /api/errors/4d0a5cb39c4a0eac.
Report an issue: GitHub.