reflex-dev/reflex · error · TypeError

`create_passthrough_component_memo` requires a component tha

Error message

`create_passthrough_component_memo` requires a component that normalizes to `rx.Component`.

What it means

`create_passthrough_component_memo` requires its function to render something that normalizes to an `rx.Component`. When the evaluated preview normalizes to `None` (e.g. the function returns None, an empty/invalid render, or a non-component value), this TypeError is raised.

Source

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

        # the memo body's hooks are computed. With the hole substituted in,
        # that walk would return nothing and the form handler would emit an
        # empty ``field_ref_mapping``. Delegate ref collection back to the
        # source component so descendants behind the hole remain visible.
        object.__setattr__(new_component, "_get_all_refs", component._get_all_refs)
        return new_component

    # Evaluate once to compute the tag from the rendered memo body shape.
    # ``_create_component_definition`` evaluates again internally; that second
    # pass appends another, identical hole to ``captured_hole_child``, and the
    # ``captured_hole_child[0]`` read below picks up the first.
    params = _analyze_params(passthrough, for_component=True)
    preview = _normalize_component_return(_evaluate_memo_function(passthrough, params))
    if preview is None:
        msg = (
            "`create_passthrough_component_memo` requires a component that "
            "normalizes to `rx.Component`."
        )
        raise TypeError(msg)
    tag = preview._compute_memo_tag()

    passthrough.__name__ = format.to_snake_case(tag)
    passthrough.__qualname__ = passthrough.__name__
    passthrough.__module__ = __name__

    definition = _create_component_definition(passthrough, Component, source_module)
    # ``export_name`` is the content-hashed tag, which reads as noise in the
    # React DevTools tree. Name the memo after the Python class it wraps.
    replacements: dict[str, Any] = {
        "auto_memo_wrapper": True,
        "display_name": type(component).__qualname__,
    }
    if definition.export_name != tag:
        replacements["export_name"] = tag
    if captured_hole_child:
        replacements["passthrough_hole_child"] = captured_hole_child[0]
    definition = dataclasses.replace(definition, **replacements)

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Ensure the function returns an actual `rx.Component` for its default parameter values
  2. Add a fallback component (e.g. `rx.fragment()`) for empty branches
  3. If you meant a value-returning memo, use `@rx.memo` directly instead of the passthrough factory

Example fix

// before
def make():
    return None  # or nothing
memo = create_passthrough_component_memo(make)

// after
def make():
    return rx.fragment()
memo = create_passthrough_component_memo(make)
Defensive patterns

Strategy: try-catch

Validate before calling

import reflex as rx

def renders_component(fn, *args) -> bool:
    try:
        return isinstance(fn(*args), rx.Component)
    except Exception:
        return False

Type guard

import reflex as rx

def is_component_returning(fn) -> bool:
    import typing
    hints = typing.get_type_hints(fn)
    ret = hints.get("return")
    return ret is not None and (ret is rx.Component or (typing.get_origin(ret) and issubclass(typing.get_origin(ret) or object, rx.Component)))

Try / catch

try:
    memo = create_passthrough_component_memo(fn)
except TypeError:
    # fall back to the public decorator which gives clearer errors
    memo = rx.memo(fn)

Prevention

When it happens

Trigger: Passing a function whose body returns `None` on the default parameters, returns a bare string/number, or whose memoized render path yields nothing the normalizer accepts.

Common situations: Building custom wrapper components with the low-level memo API where the render function has an early-return branch or was copy-pasted from a Var-returning memo.

Related errors


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