reflex-dev/reflex · error · ValueError

rx.match should have tuples of cases and one default case as

Error message

rx.match should have tuples of cases and one default case as the last argument.

What it means

rx.match's grammar is: one or more (condition, value) tuple cases, optionally followed by a single non-tuple default. If any argument other than that trailing default is a non-tuple (bare string, number, component), the structure is ambiguous and ValueError is raised.

Source

Thrown at packages/reflex-components-core/src/reflex_components_core/core/match.py:116

            ValueError: If there are multiple default cases.
        """
        if not cases:
            msg = "rx.match should have at least one case."
            raise ValueError(msg)

        if not isinstance(cases[-1], tuple):
            *cases, default_return = cases
            default_return = (
                cls._create_case_var_with_var_data(default_return)
                if not isinstance(default_return, BaseComponent)
                else default_return
            )
        else:
            default_return = None

        if any(case for case in cases if not isinstance(case, tuple)):
            msg = "rx.match should have tuples of cases and one default case as the last argument."
            raise ValueError(msg)

        if not cases:
            msg = "rx.match should have at least one case."
            raise ValueError(msg)

        return cases, default_return

    @classmethod
    def _create_case_var_with_var_data(cls, case_element: Any) -> Var:
        """Convert a case element into a Var.If the case
        is a Style type, we extract the var data and merge it with the
        newly created Var.

        Args:
            case_element: The case element.

        Returns:
            The case element Var.

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Wrap each case in a tuple: rx.match(State.x, ('a', 'Alpha'), ('b', 'Beta'), 'other')
  2. Put the default (non-tuple) only as the LAST argument
  3. When building cases from data, emit tuples: [(pattern, value), ...]

Example fix

# before
rx.match(State.size, 'small', 'large', 'unknown')
# after
rx.match(State.size, ('small', 'S'), ('large', 'L'), 'unknown')
Defensive patterns

Strategy: validation

Validate before calling

for c in cases:
    assert isinstance(c, tuple) and len(c) == 2, f'bad case: {c!r}'
result = rx.match(State.x, *cases, default)

Type guard

def valid_match_args(cases, default) -> bool:
    return bool(cases) and all(isinstance(c, tuple) and len(c) == 2 for c in cases) and not isinstance(default, tuple)

Prevention

When it happens

Trigger: `rx.match(State.x, 'a', 'b')` (bare values, no tuples); interleaving a default before tuple cases; passing lists instead of tuples for cases.

Common situations: Assuming match works like a chain of rx.cond positional pairs; forgetting the parentheses around each case; passing a default in the middle of the argument list.

Related errors


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