reflex-dev/reflex · error · TypeError

Component-returning `@rx.memo` `{fn.__name__}` must return a

Error message

Component-returning `@rx.memo` `{fn.__name__}` must return an `rx.Component` or `rx.Var[rx.Component]`.

What it means

A component-returning `@rx.memo` function must actually return an `rx.Component` or an `rx.Var[rx.Component]`. When Reflex evaluates the memo body and gets `None` (e.g. the function falls through without a return, or returns None conditionally), it raises this TypeError.

Source

Thrown at packages/reflex-base/src/reflex_base/components/memo.py:1457

        rest_target_fields: Accumulator populated with the field names of the
            component(s) the body spreads an ``rx.RestProp`` onto.
        runtime_values: Optional runtime values keyed by parameter name.

    Returns:
        The wrapped component the body returned.

    Raises:
        TypeError: If the body does not return a component.
    """
    body = _normalize_component_return(
        _evaluate_memo_function(fn, params, runtime_values)
    )
    if body is None:
        msg = (
            f"Component-returning `@rx.memo` `{fn.__name__}` must return an "
            "`rx.Component` or `rx.Var[rx.Component]`."
        )
        raise TypeError(msg)
    return _lift_rest_props(body, rest_target_fields)


def _evaluate_function_body(
    fn: Callable[..., Any], params: tuple[MemoParam, ...]
) -> ArgsFunctionOperation:
    """Run a var memo's body and build its compiled function.

    Args:
        fn: The decorated function.
        params: The analyzed memo parameters.

    Returns:
        The compiled ``ArgsFunctionOperation`` for the memo body.
    """
    return_expr = Var.create(_evaluate_memo_function(fn, params))
    _validate_var_return_expr(return_expr, fn.__name__)
    return _build_args_function(params, return_expr)

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Ensure every code path returns an `rx.Component` (e.g. `rx.fragment(...)`, `rx.box(...)`) or `rx.Var[rx.Component]`.
  2. Wrap multi-element returns in `rx.fragment` or use `rx.cond` for conditional rendering instead of returning None.
  3. If the memo is meant to compute a value, not a component, use a different mechanism (e.g. computed `rx.Var` in state) rather than a component memo.

Example fix

# before
@rx.memo
def item(label: rx.Var[str]):
    if label:
        return rx.text(label)

# after
@rx.memo
def item(label: rx.Var[str]):
    return rx.cond(label, rx.text(label), rx.text("empty"))
Defensive patterns

Strategy: validation

Validate before calling

import reflex as rx

def returns_component(fn, *args):
    result = fn(*args)
    return isinstance(result, rx.Component) or isinstance(result, rx.Var)

Type guard

import reflex as rx

def is_component_or_var(value) -> bool:
    return isinstance(value, (rx.Component, rx.Var))

Try / catch

try:
    node = memo_fn(props)
except TypeError as e:
    if "must return an" in str(e):
        return rx.fragment()  # safe placeholder while the memo body is fixed
    raise

Prevention

When it happens

Trigger: Decorating a function with `@rx.memo` whose body has no `return`, returns `None` on some path, or returns a non-component value. Raised when the memo is evaluated (`_memo_impl` / `_create_component_definition` -> `_evaluate_component_body`).

Common situations: Skeleton/stub functions decorated with `@rx.memo` before the body is written; early `return` statements (including implicit None) in branching render logic; returning a `list` or `str` instead of a single component; typos where the return statement was deleted during refactor.

Related errors


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