reflex-dev/reflex · error · TypeError

All parameters of `{fn.__name__}` must be annotated as `rx.V

Error message

All parameters of `{fn.__name__}` must be annotated as `rx.Var[...]` or `rx.RestProp`. Missing annotation for `{parameter.name}`.

What it means

Every parameter of an `@rx.memo` function must be annotated as `rx.Var[...]` (or `rx.RestProp`/`rx.EventHandler` for those kinds). This error fires when a parameter has no annotation at all, or has a 'legacy' bare annotation (e.g. `int` instead of `rx.Var[int]`), and strict-mode inference is disabled (`defaulted_params is None`). Reflex raises it at decoration time via `_analyze_params`.

Source

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

        annotation = hints.get(parameter.name, parameter.annotation)
        if _GET_TYPE_HINTS_WRAPS_NONE_DEFAULT and parameter.default is None:
            annotation = _strip_optional(annotation)
        is_missing = annotation is inspect.Parameter.empty
        # Legacy `@rx.memo` (the old `custom_component`) accepted missing and
        # bare Python-type annotations and auto-wrapped them in a `Var`. Coerce
        # both into `rx.Var[...]` and flag the parameter, so one deprecation
        # warning points the user at the params that still need an explicit
        # annotation. Strict callers (`defaulted_params is None`) reject a
        # missing annotation here; a bare type falls through to
        # `_classify_parameter`, which rejects it.
        is_legacy = defaulted_params is not None and not _is_memo_annotation(annotation)
        if is_missing or is_legacy:
            if defaulted_params is None:
                msg = (
                    f"All parameters of `{fn.__name__}` must be annotated as `rx.Var[...]` "
                    f"or `rx.RestProp`. Missing annotation for `{parameter.name}`."
                )
                raise TypeError(msg)
            if parameter.name == "children":
                annotation = Var[Component]
            elif is_missing:
                annotation = Var[Any]
            else:
                annotation = Var[annotation]
            defaulted_params.append(parameter.name)
            if is_missing and missing_params is not None:
                missing_params.append(parameter.name)

        # Children parameters by name must match the children kind exactly —
        # otherwise we accept a value-typed `children` and emit confusing JSX.
        if (
            parameter.name == "children"
            and not _children_annotation_is_valid(annotation)
            and not _is_event_handler_annotation(annotation)[0]
        ):
            msg = (

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Annotate every parameter with `rx.Var[...]` (e.g. `text: rx.Var[str]`)
  2. Use `rx.RestProp` for rest props or `rx.EventHandler` for event triggers as appropriate
  3. Enable legacy/default-inference mode if you must keep bare annotations (not recommended for new code)

Example fix

# before
@rx.memo
def greeting(name) -> rx.Var[str]:
    return "Hello " + name

# after
@rx.memo
def greeting(name: rx.Var[str]) -> rx.Var[str]:
    return "Hello " + name
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect, typing, reflex as rx

def all_params_annotated_as_var(fn) -> None:
    hints = typing.get_type_hints(fn)
    for name, p in inspect.signature(fn).parameters.items():
        if p.kind is inspect.Parameter.VAR_POSITIONAL:
            continue
        ann = hints.get(name)
        if ann is None or (typing.get_origin(ann) is not rx.Var and ann not in (rx.RestProp, rx.EventHandler)):
            raise TypeError(f"param {name!r} needs an rx.Var[...] annotation")

Type guard

import typing, reflex as rx

def memo_params_well_annotated(fn) -> bool:
    hints = typing.get_type_hints(fn)
    return all(
        typing.get_origin(ann) is rx.Var or ann in (rx.RestProp, rx.EventHandler)
        for ann in hints.values() if ann is not None
    ) and len(hints) >= len(inspect.signature(fn).parameters)

Prevention

When it happens

Trigger: Writing `@rx.memo def label(text) -> ...` (missing annotation) or `@rx.memo def label(text: str) -> ...` (bare type) in strict mode — `_analyze_params` finds `is_missing or is_legacy` with `defaulted_params is None` and raises.

Common situations: Porting a plain helper function into `@rx.memo` without adding Var annotations; relying on legacy bare-type annotations that older Reflex versions auto-wrapped; partial annotations after a refactor.

Related errors


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