reflex-dev/reflex · error · EventHandlerValueError
Form field mismatch for on_submit handler `{handler_name}`.\
Error message
Form field mismatch for on_submit handler `{handler_name}`.\n\nThe handler expects form data matching `{typed_dict_type.__name__}` with required fields:\n{_format_field_list(required_field_names)}\n\nFields missing from the form:\n{_format_field_list(missing_fields)}\n\nMatching fields present in the form:\n{_format_field_list(present_fields)}\n\nHint: Add controls with matching static `name` or `id` values, or make the TypedDict fields optional. What it means
rx.el.form.validate_on_submit type-checks that every required field of the handler's TypedDict payload has a matching form control (by static name or id). Missing fields mean the submitted event data cannot satisfy the TypedDict at runtime.
Source
Thrown at packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py:491
if not missing_fields or has_dynamic_identifiers:
continue
present_fields = tuple(
field for field in required_field_names if field in form_keys
)
msg = (
f"Form field mismatch for on_submit handler `{handler_name}`.\n\n"
f"The handler expects form data matching `{typed_dict_type.__name__}` "
"with required fields:\n"
f"{_format_field_list(required_field_names)}\n\n"
"Fields missing from the form:\n"
f"{_format_field_list(missing_fields)}\n\n"
"Matching fields present in the form:\n"
f"{_format_field_list(present_fields)}\n\n"
"Hint: Add controls with matching static `name` or `id` values, or "
"make the TypedDict fields optional."
)
raise EventHandlerValueError(msg)
def _get_vars(
self, include_children: bool = True, ignore_ids: set[int] | None = None
) -> Iterator[Var]:
yield from super()._get_vars(
include_children=include_children, ignore_ids=ignore_ids
)
yield from self._get_form_refs().values()
def _exclude_props(self) -> list[str]:
return [
*super()._exclude_props(),
"reset_on_submit",
"handle_submit_unique_name",
]
HTMLInputTypeAttribute = Literal[View on GitHub (pinned to 45b8ed5ab7)
Solutions
- Add form controls whose static name or id matches each required TypedDict field
- Use static string names: rx.input(name="email") instead of a Var-driven name
- Make genuinely optional TypedDict fields NotRequired
- Wrap dynamically-built forms in rx.el.form without validate_on_submit, or restructure so names are static
Example fix
# before
class FormData(TypedDict):
email: str # form has rx.input(placeholder="email") only
rx.el.form(..., validate_on_submit=True, on_submit=State.handle)
# after
rx.el.form(rx.input(name="email"), validate_on_submit=True, on_submit=State.handle) Defensive patterns
Strategy: validation
Validate before calling
required = {k for k, t in FormData.__annotations__.items() if k not in getattr(FormData, '__optional_keys__', set())}
form_names = {'email', 'password'} # names you actually render
missing = required - form_names
assert not missing, f'missing form controls: {missing}' Type guard
def typeddict_required_fields(td: type[TypedDict]) -> set[str]:
return set(td.__annotations__) - set(getattr(td, '__optional_keys__', set())) Prevention
- Use static name= strings on every control matching TypedDict keys
- Mark optional fields with NotRequired
- Add new TypedDict fields and inputs in the same commit
When it happens
Trigger: Using on_submit with an event handler whose parameter is a TypedDict with required keys, while the form lacks inputs whose static name/id equals those keys — e.g. controls with dynamic/placeholder names, or fields rendered conditionally.
Common situations: Adding a required TypedDict field but forgetting to add the input; using rx.input(name=State.dynamic_name) so the name is not static; renaming TypedDict keys without renaming inputs.
Related errors
- Var-returning `@rx.memo` `{func_name}` cannot depend on embe
- Invalid prop(s) {invalid_fields_str} for {component_name!r}.
- default_color_mode must be one of {allowed_color_modes}, but
- Invalid event chain: {value!s} of type {value._var_type}
- Invalid event: {v}
AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28).
Data as JSON: /api/errors/c4b402c4031e9deb.
Report an issue: GitHub.