{"record":{"id":"84be4bed7e6a09ea","repo":"reflex-dev/reflex","slug":"create-passthrough-component-memo-requires-a-com","errorCode":null,"errorMessage":"`create_passthrough_component_memo` requires a component that normalizes to `rx.Component`.","messagePattern":"`create_passthrough_component_memo` requires a component that normalizes to `rx\\.Component`\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/reflex-base/src/reflex_base/components/memo.py","lineNumber":1920,"sourceCode":"        # the memo body's hooks are computed. With the hole substituted in,\n        # that walk would return nothing and the form handler would emit an\n        # empty ``field_ref_mapping``. Delegate ref collection back to the\n        # source component so descendants behind the hole remain visible.\n        object.__setattr__(new_component, \"_get_all_refs\", component._get_all_refs)\n        return new_component\n\n    # Evaluate once to compute the tag from the rendered memo body shape.\n    # ``_create_component_definition`` evaluates again internally; that second\n    # pass appends another, identical hole to ``captured_hole_child``, and the\n    # ``captured_hole_child[0]`` read below picks up the first.\n    params = _analyze_params(passthrough, for_component=True)\n    preview = _normalize_component_return(_evaluate_memo_function(passthrough, params))\n    if preview is None:\n        msg = (\n            \"`create_passthrough_component_memo` requires a component that \"\n            \"normalizes to `rx.Component`.\"\n        )\n        raise TypeError(msg)\n    tag = preview._compute_memo_tag()\n\n    passthrough.__name__ = format.to_snake_case(tag)\n    passthrough.__qualname__ = passthrough.__name__\n    passthrough.__module__ = __name__\n\n    definition = _create_component_definition(passthrough, Component, source_module)\n    # ``export_name`` is the content-hashed tag, which reads as noise in the\n    # React DevTools tree. Name the memo after the Python class it wraps.\n    replacements: dict[str, Any] = {\n        \"auto_memo_wrapper\": True,\n        \"display_name\": type(component).__qualname__,\n    }\n    if definition.export_name != tag:\n        replacements[\"export_name\"] = tag\n    if captured_hole_child:\n        replacements[\"passthrough_hole_child\"] = captured_hole_child[0]\n    definition = dataclasses.replace(definition, **replacements)","sourceCodeStart":1902,"sourceCodeEnd":1938,"githubUrl":"https://github.com/reflex-dev/reflex/blob/45b8ed5ab735f8a56bbb09a42384f030eb0208e7/packages/reflex-base/src/reflex_base/components/memo.py#L1902-L1938","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the function returns an actual `rx.Component` for its default parameter values","Add a fallback component (e.g. `rx.fragment()`) for empty branches","If you meant a value-returning memo, use `@rx.memo` directly instead of the passthrough factory"],"exampleFix":"// before\ndef make():\n    return None  # or nothing\nmemo = create_passthrough_component_memo(make)\n\n// after\ndef make():\n    return rx.fragment()\nmemo = create_passthrough_component_memo(make)","handlingStrategy":"try-catch","validationCode":"import reflex as rx\n\ndef renders_component(fn, *args) -> bool:\n    try:\n        return isinstance(fn(*args), rx.Component)\n    except Exception:\n        return False","typeGuard":"import reflex as rx\n\ndef is_component_returning(fn) -> bool:\n    import typing\n    hints = typing.get_type_hints(fn)\n    ret = hints.get(\"return\")\n    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)))","tryCatchPattern":"try:\n    memo = create_passthrough_component_memo(fn)\nexcept TypeError:\n    # fall back to the public decorator which gives clearer errors\n    memo = rx.memo(fn)","preventionTips":["Smoke-test the render function with default params before registering it","Always return rx.fragment() from empty branches"],"tags":["reflex","memo","passthrough","component-return"],"backgroundTag":"invalid-return-type","analyzedSha":"45b8ed5ab735f8a56bbb09a42384f030eb0208e7","analyzedAt":"2026-08-28T19:25:27.644Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}