{"record":{"id":"c4b402c4031e9deb","repo":"reflex-dev/reflex","slug":"form-field-mismatch-for-on-submit-handler-handle","errorCode":null,"errorMessage":"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.","messagePattern":"Form field mismatch for on_submit handler `(.+?)`\\.\\\\n\\\\nThe handler expects form data matching `(.+?)` with required fields:\\\\n(.+?)\\\\n\\\\nFields missing from the form:\\\\n(.+?)\\\\n\\\\nMatching fields present in the form:\\\\n(.+?)\\\\n\\\\nHint: Add controls with matching static `name` or `id` values, or make the TypedDict fields optional\\.","errorType":"exception","errorClass":"EventHandlerValueError","httpStatus":null,"severity":"error","filePath":"packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py","lineNumber":491,"sourceCode":"            if not missing_fields or has_dynamic_identifiers:\n                continue\n\n            present_fields = tuple(\n                field for field in required_field_names if field in form_keys\n            )\n            msg = (\n                f\"Form field mismatch for on_submit handler `{handler_name}`.\\n\\n\"\n                f\"The handler expects form data matching `{typed_dict_type.__name__}` \"\n                \"with required fields:\\n\"\n                f\"{_format_field_list(required_field_names)}\\n\\n\"\n                \"Fields missing from the form:\\n\"\n                f\"{_format_field_list(missing_fields)}\\n\\n\"\n                \"Matching fields present in the form:\\n\"\n                f\"{_format_field_list(present_fields)}\\n\\n\"\n                \"Hint: Add controls with matching static `name` or `id` values, or \"\n                \"make the TypedDict fields optional.\"\n            )\n            raise EventHandlerValueError(msg)\n\n    def _get_vars(\n        self, include_children: bool = True, ignore_ids: set[int] | None = None\n    ) -> Iterator[Var]:\n        yield from super()._get_vars(\n            include_children=include_children, ignore_ids=ignore_ids\n        )\n        yield from self._get_form_refs().values()\n\n    def _exclude_props(self) -> list[str]:\n        return [\n            *super()._exclude_props(),\n            \"reset_on_submit\",\n            \"handle_submit_unique_name\",\n        ]\n\n\nHTMLInputTypeAttribute = Literal[","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/reflex-dev/reflex/blob/45b8ed5ab735f8a56bbb09a42384f030eb0208e7/packages/reflex-components-core/src/reflex_components_core/el/elements/forms.py#L473-L509","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nclass FormData(TypedDict):\n    email: str  # form has rx.input(placeholder=\"email\") only\nrx.el.form(..., validate_on_submit=True, on_submit=State.handle)\n# after\nrx.el.form(rx.input(name=\"email\"), validate_on_submit=True, on_submit=State.handle)","handlingStrategy":"validation","validationCode":"required = {k for k, t in FormData.__annotations__.items() if k not in getattr(FormData, '__optional_keys__', set())}\nform_names = {'email', 'password'}  # names you actually render\nmissing = required - form_names\nassert not missing, f'missing form controls: {missing}'","typeGuard":"def typeddict_required_fields(td: type[TypedDict]) -> set[str]:\n    return set(td.__annotations__) - set(getattr(td, '__optional_keys__', set()))","tryCatchPattern":null,"preventionTips":["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"],"tags":["reflex","form","typeddict","validation"],"backgroundTag":"form-schema-mismatch","analyzedSha":"45b8ed5ab735f8a56bbb09a42384f030eb0208e7","analyzedAt":"2026-08-28T19:25:27.644Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}