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 out

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Look at {type(e)} in the message to identify the offending value
  2. Wrap plain functions with rx.event / ensure you return EventSpec-producing calls (e.g. call the handler: State.my_handler())
  3. 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

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


AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28). Data as JSON: /api/errors/4d0a5cb39c4a0eac. Report an issue: GitHub.