reflex-dev/reflex · error · TypeError

OTP field high-level wrapper requires a static integer `leng

Error message

OTP field high-level wrapper requires a static integer `length`. Pass children explicitly for dynamic lengths.

What it means

The high-level rx.otp_field() wrapper must know how many input slots to render, so it requires a compile-time integer `length`. Passing a Var, string, bool, or omitting it leaves the wrapper unable to generate the N OTPFieldInput children. Reflex throws TypeError because the component tree is built at compile time in Python, not at runtime in the browser.

Source

Thrown at packages/reflex-components-internal/src/reflex_components_internal/components/base/otp_field.py:187

        Raises:
            ValueError: If `length` is missing when children are supplied, or
                if `length` is not a positive integer when children are
                auto-generated.
            TypeError: If `length` is not an integer when children are
                auto-generated (a Var can only be used with explicit children).
        """
        if children:
            if "length" not in props:
                msg = "OTP field `length` is required when passing children explicitly."
                raise ValueError(msg)
        else:
            length = props.setdefault("length", 6)
            if not isinstance(length, int) or isinstance(length, bool):
                msg = (
                    "OTP field high-level wrapper requires a static integer `length`."
                    " Pass children explicitly for dynamic lengths."
                )
                raise TypeError(msg)
            if length <= 0:
                msg = "OTP field `length` must be a positive integer."
                raise ValueError(msg)
            children = tuple(OTPFieldInput.create() for _ in range(length))

        return OTPFieldRoot.create(*children, **props)


class OTPField(ComponentNamespace):
    """Namespace for OTP field components."""

    root = staticmethod(OTPFieldRoot.create)
    input = staticmethod(OTPFieldInput.create)
    separator = staticmethod(OTPFieldSeparator.create)
    class_names = ClassNames
    __call__ = staticmethod(HighLevelOTPField.create)

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Pass a static integer: rx.otp_field(length=6)
  2. For dynamic lengths, compose the low-level parts explicitly: rx.otp_field.root(*[rx.otp_field.input() for _ in range(n)])
  3. If length comes from state, fix it to a constant at compile time and hide/show slots instead

Example fix

# before
rx.otp_field(length=State.otp_length)
# after
rx.otp_field(length=6)
Defensive patterns

Strategy: type-guard

Validate before calling

length = 6
assert isinstance(length, int) and not isinstance(length, bool), 'length must be a static int'

Type guard

def is_static_int(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool)

Prevention

When it happens

Trigger: Calling rx.otp_field() without `length`, passing length="6" (string), length=State.var (a Var), or length=True (bool passes isinstance int check but is explicitly rejected).

Common situations: Trying to make OTP length dynamic from state (e.g. length=AppState.digits), or assuming a default exists because the low-level OTPFieldRoot/OTPFieldInput API is used elsewhere.

Related errors


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